使用迭代器擦除容器元素

发布于 2024-10-08 15:19:02 字数 1819 浏览 0 评论 0原文

我当前的作业要求我为列表创建一个迭代器类。我一直致力于创建一个好的 erase(iterator where) 函数。

当前代码(减少以适应问题):

class List
{
    class _Iter
    {
        friend class List;
    public:
        _Iter(ListElem *pCurr, List *pList);

        /* *, ->, ++, --, == and != operators overloaded */

    private:
        ListElem *pCurr_; List *pList_;
    };

    typedef _Iter iterator;

    iterator erase(iterator where);
};

擦除的实现如下:

// Precondition: List has been checked for size > 0.
List::iterator List::erase(List::iterator& where)
{
    // Erasing only element in list.
    if(where == end() && where == begin())
    {
        pop_back(); // or pop_front();
        return iterator(0, this);
    }

    // Elem at end
    if(where == end())
    {
        pop_back();
        return end();
    }
    else 
    {
        // Elem at beginning
        if(where == begin())
        {
            pop_front();
            return ++begin();
        }
    }

    // Elem somewhere between beginning and end.
    iterator temp(where);
    // The node next to pCurr_ should point to the one before pCurr_
    where.pCurr_->next->prev = where.pCurr_->prev;
    // The node before pCurr_ should point to the one after pCurr_
    where.pCurr_->prev->next = where.pCurr_->next;
    // Return the node after pCurr_
    ++temp;
    delete where.pCurr_;
    --size_;
    return temp;
} 

前三种情况 - 仅元素、末尾元素和开头元素 - 都可以。编码良好,完全不需要 _Iter 成员的知识和私人访问权限。但是,如果该元素不在这些位置,那么我(似乎)别无选择,只能违反封装并直接更改 pCurr_ (列表的元素)。

有什么办法可以避免这种情况吗?我查看了 STL 列表,但他们使用了一些其他函数 _Next_Node_(/* stuff */)_Prev_Node_(/* stuff */) ,这些函数不是很有用大部头书。谷歌搜索给了我关于如何使用擦除功能的有用结果,而不是如何自己编写它。

问题:有没有一种方法可以删除迭代器指向的元素,而不必获取它的 pCurr_ 成员?

My current homework assignment has me creating an iterator class for a list. I'm stuck at creating a good erase(iterator where) function.

Current code (reduced to fit question):

class List
{
    class _Iter
    {
        friend class List;
    public:
        _Iter(ListElem *pCurr, List *pList);

        /* *, ->, ++, --, == and != operators overloaded */

    private:
        ListElem *pCurr_; List *pList_;
    };

    typedef _Iter iterator;

    iterator erase(iterator where);
};

with the erase being implemented like so:

// Precondition: List has been checked for size > 0.
List::iterator List::erase(List::iterator& where)
{
    // Erasing only element in list.
    if(where == end() && where == begin())
    {
        pop_back(); // or pop_front();
        return iterator(0, this);
    }

    // Elem at end
    if(where == end())
    {
        pop_back();
        return end();
    }
    else 
    {
        // Elem at beginning
        if(where == begin())
        {
            pop_front();
            return ++begin();
        }
    }

    // Elem somewhere between beginning and end.
    iterator temp(where);
    // The node next to pCurr_ should point to the one before pCurr_
    where.pCurr_->next->prev = where.pCurr_->prev;
    // The node before pCurr_ should point to the one after pCurr_
    where.pCurr_->prev->next = where.pCurr_->next;
    // Return the node after pCurr_
    ++temp;
    delete where.pCurr_;
    --size_;
    return temp;
} 

The first three cases- only element, element at end and element at beginning- are all okay. Coded fine and need absolutely no knowledge and private access to _Iters members. However, if the element is not in those positions, then I have (seemingly) no choice but to violate the encapsulation and change pCurr_ (element of the list) directly.

Is there any way to avoid this? I looked inside the STL list, but they used some other functions _Next_Node_(/* stuff */) and _Prev_Node_(/* stuff */) that weren't very useful to me. Google searches give me helpful results on how to use the erase function, not how to write it myself.

Question: Is there a way in which I can erase the element pointed to by my iterator without having to grab it's pCurr_ member?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

毅然前行 2024-10-15 15:19:02
  1. 请勿使用以下划线开头且后跟大写字母的标识符。它们是为标准库和系统编写者保留的。虽然您正在编写自己的列表类,但实际上并不是在编写标准库。

  2. end() 通常是列表末尾之后的一个元素,而不是最后一个元素。 (要获取列表的实际最后一个迭代器,您可以在发生时执行 l.rbegin().base() )。

  3. 按值传递迭代器,而不是非常量引用。

  4. 为什么你如此关心修改 pCurr?

  1. Do not use identifiers beginning with underscore followed by an uppercase letter. They are reserved for standard library and system writers. Although you are writing your own list class, you are not actually writing the standard library.

  2. end() is normally one element past the end of the list, not the last element. (To get the actual last iterator of the list you can do l.rbegin().base() as it happens).

  3. Pass the iterator by value, not non-const reference.

  4. Why are you so concerned with modifying pCurr?

缺⑴份安定 2024-10-15 15:19:02

这并没有真正违反封装性。容器及其迭代器紧密耦合几乎是不可避免的。它们两者一起向用户隐藏实现细节。如果他们彼此不是朋友,则必须将更多实现细节泄露给用户。如果相关类有充分的理由了解彼此的内部结构,friend 关键字可以增强封装性。

请注意,表示包含一个元素的列表的 begin() == end() 不是标准库约定,它意味着容器为空。 end() 应该返回一个指向容器“最后一个”的迭代器。

This is not really violating encapsulation. It is pretty much inevitable that a container and its iterators are tightly coupled. The two of them together hide the implementation details from the user. If they weren't friends to each other, more implementation details would have to be leaked to the user. The friend keyword can enhance encapsulation if the classes in question have valid reasons to know about each others internals.

Note that begin() == end() representing a list with one element is not the standard library convention where it means that the container is empty. end() should return an iterator to "one-past-the-end" of the container.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文