为什么std :: set似乎强制使用const_iterator?

时间:2016-08-04 13:16:01

标签: c++ c++11 stdset

考虑下面的简单程序,它试图使用对其中元素的NON-const引用来遍历集合的值:

#include <set>
#include <iostream>

class Int
{
public:
   Int(int value) : value_(value) {}
   int value() const { return value_; }
   bool operator<(const Int& other) const { return value_ < other.value(); }
private:
   int value_;
};

int
main(int argc, char** argv) {
   std::set<Int> ints;
   ints.insert(10);
   for (Int& i : ints) {
      std::cout << i.value() << std::endl;
   }
   return 0;
}

编译时,我从gcc收到错误:

test.c: In function ‘int main(int, char**)’:
test.c:18:18: error: invalid initialization of reference of type ‘Int&’ from expression of type ‘const Int’  
for (Int& i : ints) {  
              ^  

是的,我知道我实际上并没有尝试修改for循环中的元素。但重点是我应该能够在循环内部使用非const引用,因为set本身不是const限定的。如果我创建一个setter函数并在循环中使用它,我会得到同样的错误。

4 个答案:

答案 0 :(得分:39)

集合就像没有值的地图,只有键。由于这些键用于加速集合操作的树,因此它们无法更改。因此,所有元素都必须是const,以防止底层树的约束被破坏。

答案 1 :(得分:9)

std::set使用包含的值来形成快速数据结构(通常是红黑树)。更改值意味着需要更改整个结构。因此,强制conststd::set会阻止您将其推入不可用状态。

答案 2 :(得分:7)

来自cpp reference

  

在一个集合中,元素的值也标识它(值为   本身是T)类型的密钥,每个值必须是唯一的。价值   集合中的元素中的元素不能被修改一次(   元素总是 const ),但可以插入或删除它们   容器。

答案 3 :(得分:4)

行为是设计的。

给你一个非const迭代器可以激发你改变集合中的元素;随后的迭代行为将是未定义的。

请注意,C ++标准说set<T>::iteratorconst,所以旧式的C ++ 11之前的方法仍然不起作用。