【问题标题】:iterate over non-const std::unordered_set迭代非常量 std::unordered_set
【发布时间】:2017-11-27 05:07:05
【问题描述】:

我有一个 std::unordered_set,其中包含 bar 类的实例。

我想遍历集合中的所有 bars 并在每个上调用一些 void foo(bar& b) 函数。

您可能会从函数签名中注意到我希望foo 以某种方式更改bar& b 参数的状态。

现在,我知道foo 不会以影响散列或相等比较的方式更改bar,但我仍然有问题。

但是,我对集合进行了迭代,我希望得到的最好结果是 const bar&,这显然是行不通的。

我可以想到几种可能的方法:

  1. 使用const_cast。不知道这是否可行(还)。这对我来说有点难闻,但我很高兴能开悟!!
  2. 使用std::unordered_map而不是std::unordered_set,这样即使我只能得到密钥的const,我也可以使用该密钥查找bar对象并安全地调用foo on它。

非常感谢您的建议!

提前致谢!

【问题讨论】:

    标签: c++11 iterator constants unordered-map unordered-set


    【解决方案1】:

    this answer 已经展示了一些干净的解决方案。

    另一种干净的方法是通过指针添加一个间接层。即使指针本身是const指向的数据也不会是:

    struct Bar
    {
        int key;
        std::unique_ptr<int> pValue;
    };
    
    std::unordered_set< Bar, BarHash, BarEqual > bars;
    
    for( const auto& bar : bars )
    {
        // Works because only the pointer is constant, not the data pointed to.
        *bar.pValue = 42;
    }   
    

    这显然有额外的内存分配开销、存储指针所需的空间以及通过指针访问值时的间接性。

    如果您想保留 值语义,您还必须编写自定义复制构造函数和赋值运算符。

    【讨论】:

      【解决方案2】:

      使用const_cast。不知道这是否可行(还)。对我来说有点难闻,但我很高兴能开悟!

      是的,它会起作用的。您可以轻松地重载foo(bar const&amp;)const_cast 引用,然后调用foo(bar&amp;)。我同意你的观点,它闻起来很糟糕,并且表明设计存在缺陷。您可能想重新审视设计,看看是否有干净的解决方案。

      使用std::unordered_map 而不是std::unordered_set,这样即使我只能获取键的常量,我也可以使用该键来查找 bar 对象并安全地调用 foo

      这与第一种方法没有太大区别。 std::unordered_set&lt;T&gt; 本质上是 std::unordered_map&lt;T, bool&gt;

      潜在的清洁解决方案:

      1. 从集合中获取对象的副本,从集合中删除条目,更新副本,然后将副本放回集合中。如果这被证明太贵了……

      2. 使用std::vector&lt;Bar&gt;。你可以从向量中得到一个Bar&amp;,一切都很好。

      3. 将不影响其哈希值的Bar 的成员变量设为mutable。然后,您可以只使用 foo(Bar const&amp;) 并使用对集合中对象的引用直接调用它。

      【讨论】:

      • 需要注意的是mutable只适用于简单的结构。如果你有一个只能通过非常量设置器访问的私有成员的类,你仍然需要一个const_cast
      • const_cast 是未定义的行为,如果 unordered_set 保持 const 指向声明为 const 的对象的指针。
      • @jbapple,OP 没有在unordered_set 中存储指向const 对象的指针。他们正在存储对象。
      • unordered_set 通常存储指向对象的指针。在每个 insert 上分配一个新的 const 对象,然后将指向它的指针存储在哈希表中是符合标准的。该指针将是 const T *,因为对象将是 const T,因此 const_cast 将是 UB。
      • 关于 unordered_set 是一个带有布尔值的 unordered_map 的有趣点!谢谢!
      猜你喜欢
      • 2013-09-13
      • 1970-01-01
      • 2020-11-23
      • 1970-01-01
      • 2017-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多