【问题标题】:Assigning a new value to a iterator of a intrusive container为侵入式容器的迭代器分配新值
【发布时间】:2015-01-25 18:00:56
【问题描述】:

在使用 boost 侵入式容器 splay_set 时,我必须重置本地迭代器成员变量。请参阅下面的示例代码 -

#include <boost/intrusive/splay_set.hpp>

using namespace boost::intrusive;

class Obj
{
    public:
        Obj(){};
        ~Obj(){};

        boost::intrusive::list_member_hook<boost::intrusive::link_mode<boost::intrusive::normal_link> > m_memberHook;
    private:
        int a;
};

typedef splay_set<Obj, compare<greater<Obj> >, member_hook<Obj, 
                splay_set_member_hook<boost::intrusive::link_mode<boost::intrusive::normal_link> >,
                &Obj::m_memberHook> > StorageSSet;
typedef StorageSSet::iterator   StorageSSetIter;

class Storage
{
    public:

        bool init(StorageSSet& sset)
        {
            // Error: "no match for operator= in ..."
            m_curIter = sset.begin();  ////<<<<------------- How to set new iterator
            m_endIter = sset.end();    ////<<<<------------- How to set new iterator
        }

    protected:

        StorageSSetIter     m_curIter;
        StorageSSetIter     m_endIter;
};

我想侵入式容器不支持分配。我也无法通过成员初始化器列表初始化 splay_set 迭代器。 boost 和其他网站上的例子非常有限。没有人对这个问题给出明确的答案。

我的问题是我应该怎么做才能为 splay_set 迭代器(一般意义上的侵入式容器)分配一个新值。

【问题讨论】:

  • 第一步是发布您的实际代码。您发布的不是有效的 C++:“Class”不是 C++ 关键字,未定义 list_member_hook,typedef 中有两个连续的逗号等。将值分配给无效类型是行不通的。
  • @Manish Re:编辑,如果没有operator&lt;(std::?)greater&lt;Obj&gt; 将如何工作?
  • @sehe 我知道,我只是懒得写很多示例代码:/
  • 糟糕。那是 not just sample code。所以,它也不是 just being lazy :)

标签: c++ boost iterator intrusive-containers


【解决方案1】:

你得到const_iterators的原因主要是因为修改字段可能会破坏容器不变量。

例如在跨struct { int key; std::string value; };的元素构建集合时,通过迭代器修改key字段会导致[Undefined Behaviour]

更新内容的干净方法是先删除,然后重新插入修改后的项目。

如果这真的太严重地损害性能

  1. 重新考虑您的设计(考虑 mutable 非关键字段的成员,考虑通过引用包含非关键数据)
  2. 通过使用const_cast&lt;&gt; 在抽象中打一个洞来抛弃常量。 危险不要将此引用传递给任何其他方,因为他们可能会破坏容器不变量,因为他们可能不知道单独留下关键字段

【讨论】:

  • 我不确定上面代码中的 StorageSSetIter 是否为 const_iterator。我在想侵入式容器分配运算符是私有的,因为它会导致一个新副本,这将破坏使用侵入式容器的目的。这种设计是因为我必须支持在不同数据结构上运行的多个服务。我必须用迭代器模式将它们统一在一个接口中。
  • @Manish 你同时在谈论不同的事情。复制迭代器!=复制元素。 (同样,删除和重新插入相同的元素不需要元素的副本,因此不会违背使用侵入式容器的“目的”(顺便说一句,有很多目的))。最后,有一个简单的方法可以验证sset.begin() 的类型:只需输入struct {} _ = sset.begin() 并仔细检查编译器错误。
  • 您的评论在我的上下文中是有意义的。您的建议给了我一些要点,我需要从我正在使用的客户端 api 检查。
  • 这正是我所面临的问题。示例代码错误引导并反映了我认为的情况,但您当时就发现了问题。奇妙。谢谢人
猜你喜欢
  • 2019-04-06
  • 2020-04-21
  • 1970-01-01
  • 2010-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-02
  • 2021-02-11
相关资源
最近更新 更多