【问题标题】:Get a std::list::iterator from std::reference_wrapper从 std::reference_wrapper 获取 std::list::iterator
【发布时间】:2020-12-23 15:17:44
【问题描述】:

我正在用 C++ 编写一个斐波那契堆数据结构 (https://en.wikipedia.org/wiki/Fibonacci_heap)。 这个数据结构由几个堆组成,根连接在一个双向链表中。每个节点都有一个其子节点的双向链表。整个堆有一个叶子节点的双向链表,以支持快速修剪。 (CLRS 19-3.b)

我对@9​​87654322@ 的实现是:

struct Node {
        using Iterator = std::list<std::unique_ptr<Node>>::iterator;
        using LeafIterator = std::list<std::reference_wrapper<std::unique_ptr<Node>>>::iterator;
        Iterator parent;
        std::list<std::unique_ptr<Node>> child_list;
        T key;
        bool mark = false;
        bool is_leaf = false;
        LeafIterator leaf_iterator;
        Node(const T& key) : key {key} {}
    };

我对@9​​87654324@ 的实现是:

    using Iterator = std::list<std::unique_ptr<Node>>::iterator;
    using LeafIterator = std::list<std::reference_wrapper<std::unique_ptr<Node>>>::iterator;

    std::list<std::unique_ptr<Node>> NIL;
    std::list<std::unique_ptr<Node>> root_list;
    std::list<std::reference_wrapper<std::unique_ptr<Node>>> leaf_list;
    Iterator min_element;

我用std::list&lt;std::reference_wrapper&lt;std::unique_ptr&lt;Node&gt;&gt;&gt;代替leaf_list,而不是std::list&lt;Node*&gt;,因为叶子节点的内存完全归其父节点所有,我不希望双重删除崩溃。

当我尝试删除叶节点时出现问题。我可以通过leaf_list.begin() 访问要删除的叶节点,但无法从其父节点的child_list 中删除它。

我认为有两种可能的解决方法:

  • parentchild_list 执行线性扫描以获得与给定叶子匹配的std::list&lt;std::unique_ptr&lt;Node&gt;&gt;::iterator。这是线性扫描,太慢了。
  • 抛弃leaf_list 并保留两个指针作为Node 的成员变量,其中包含prev_leafnext_leaf 以模拟双向链表。我不喜欢这样,因为它会使Nodes 更加臃肿。
  • ...暂时想不到别的了

在这种情况下,从std::reference_wrapper 获取std::list&lt;std::unique_ptr&lt;Node&gt;&gt;::iterator 的最佳方法是什么?

【问题讨论】:

    标签: c++ linked-list iterator


    【解决方案1】:

    使用std::list&lt;Node*&gt; 不会导致任何双重删除,只要您不手动删除节点,并让child_list 成员中的实际unique_ptr 指针处理该问题。您只需要小心避免在 Node 被销毁后使用悬空指针。但是这种方式仍然不能很好地从适当的child_list 中快速删除Node*

    相反,您可以使用std::list&lt;Iterator&gt; leaf_list;。这是相对安全的,因为在 std::list 上的插入和擦除不会使任何迭代器无效(当然,擦除元素的迭代器除外)。

    虽然你仍然有一个不变量要遵循,leaf_list 中的迭代器属于适当的child_list,但最好帮助代码遵循它。根据该类的预期用途和一般性,这可能意味着只需在 struct Node 定义之内或之前将注释放在 cmets 中。或者这可能意味着使Node 成为具有private 成员和更安全public 接口的适当类-我可能会考虑使用boost::iterator_adaptor 创建自定义迭代器,以允许在叶节点上进行迭代,而不会破坏不变量的危险。如果您不期望重用,但发现它在更多的上下文或项目中再次有用,您当然可以稍后更改这些类型的决策(除非使用原始方式编写了太多代码)。

    【讨论】:

    • 好,我切换到std::list&lt;Iterator&gt; leaf_list,效果很好!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-13
    • 2017-12-09
    • 2017-04-21
    • 1970-01-01
    • 1970-01-01
    • 2017-07-31
    相关资源
    最近更新 更多