【问题标题】:std::forward_list -- erasing with a stored iteratorstd::forward_list -- 用存储的迭代器擦除
【发布时间】:2013-09-20 04:05:30
【问题描述】:

我正在尝试保留特定(基)类实例的全局列表,以便我可以随时通过遍历此全局列表来跟踪它们。

我认为解决此问题的最合适方法是使用侵入性列表。例如,我听说可以通过深入研究 Linux 内核来遇到这些生物。

在我所处的情况下,我真的不需要这样的性能保证,而且使用侵入式列表会使事情变得有些复杂。

到目前为止,我已经实现了一个知道其所有实例的类的概念。

class A {
    static std::forward_list<A*> globallist;
    std::forward_list<A*>::iterator listhandle;
public:
    A() {
        globallist.push_front(this);
        listhandle = globallist.begin();
    }
    virtual ~A() {
        globallist.erase_after(...);  // problem
    }
};

问题在于没有forward_list::erase(),而且看起来确实不像将globallist.before_begin() 保存在ctor 中对我有好处。我永远不应该取消引用before_begin() 的迭代器。它真的会保住这个位置吗?如果我保存 before_begin 的迭代器,然后 push_front() 一个新项目,该迭代器可能仍然无法取消引用,但它可以发送到 erase_after() 吗?

【问题讨论】:

    标签: c++ c++11 linked-list intrusive-containers forward-list


    【解决方案1】:

    forward_list 是一个单链表。要删除中间的节点,您必须有一个指向前一个节点的指针,不知何故。例如,您可以这样做:

    class A {
        static std::forward_list<A*> globallist;
        std::forward_list<A*>::iterator prev_node;
    public:
        A() {
            A* old_head = globallist.front();
            globallist.push_front(this);
            prev_node = globallist.before_begin();
            old_head->prev_node = globallist.begin();
        }
    };
    

    将第一个元素推入空列表的情况以及删除逻辑留给读者练习(删除时,将您的prev_node复制到下一个节点的prev_node)。

    或者,只需使用std::list 即可避免所有这些麻烦。

    【讨论】:

    • 我希望所有这些体操都不是必需的。将被移除节点的prev分配给下一个节点的prev不会由erase_after()执行吗?
    • erase_after 怎么知道你的班级有什么?它所知道的只是它持有一些指针。使用std::list,那些体操将实际上变得不必要了。
    • 我的课程不是用来保存前一个节点的。它旨在保留列表中的位置(因此删除可能是 O(1))。我只想调用erase() 来擦除该位置即将失效的指针(指向正在销毁的我自己)。无论如何,谢谢,我一定会把它设为std::list。
    • 在您最喜欢的数据结构教科书中了解单链表。这不是它的工作原理。
    • 哦,我想我看到了问题所在。必须知道前一个节点才能从单链表中正确删除......但是由于单链表不跟踪甚至不知道它,所以它的管理由我决定。我这样做所节省的只是 N-1 个指针占用的空间。
    猜你喜欢
    • 2021-05-08
    • 2013-04-22
    • 1970-01-01
    • 1970-01-01
    • 2011-09-23
    • 2011-03-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多