Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/149.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么std::set似乎强制使用常量迭代器?_C++_C++11_Stdset - Fatal编程技术网

C++ 为什么std::set似乎强制使用常量迭代器?

C++ 为什么std::set似乎强制使用常量迭代器?,c++,c++11,stdset,C++,C++11,Stdset,考虑下面的简单程序,它尝试使用对集合中元素的非常量引用来迭代集合的值: #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_ <

考虑下面的简单程序,它尝试使用对集合中元素的非常量引用来迭代集合的值:

#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;
}

是的,我知道我实际上并没有试图修改for循环中的元素。但问题是,我应该能够得到一个非常量引用来在循环中使用,因为集合本身不是常量限定的。如果我创建一个setter函数并在循环中使用它,我会得到同样的错误。

一个集合就像一个没有值,只有键的映射。由于这些键用于加速集合上操作的树,因此它们不能更改。因此,所有元素都必须是常量,以防止底层树的约束被破坏。

行为是通过设计实现的

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


< C++ >注意,C++标准称:“代码>集合:迭代器< /代码>是代码> const 。因此旧式的Pc++ 11方式仍然不能工作。

<代码>代码:STD::SET//COD>使用包含的值来形成快速数据结构(通常是红黑树)。更改值意味着需要更改整个结构。因此,强制
const
ness,
std::set
可防止您将其推入不可用状态。

来自:

在集合中,元素的值也标识它(值为 它本身是类型为T)的键,并且每个值必须是唯一的。价值 在容器中一次不能修改集合中元素的个数() 元素始终是常量,但可以从中插入或删除 集装箱


“不可用”,如“尝试使用时随机崩溃”。@Yakk更可能在某些操作中找不到元素,这可能更糟糕。我在这里详细解释了这一点:如果您确实想修改
std::set
的元素,可以使用
const\u cast
。只需确保修改不会改变集合中元素的顺序,否则您将遇到未定义的行为。这是非常不安全的,这就是为什么你必须不厌其烦地去做。我明白了,但我可能在修改集合元素中的某个东西,它不会修改集合中的排序顺序;声明一个非常量集将从begin()返回一个非常量迭代器std::set无法知道这一点,因此它使所有
const
都变得安全。如果您的结构具有可变数据和一些不可变的键字段,那么您可能应该使用一个映射,该映射的值为结构,键为不可变键字段的副本。如果你知道你没有改变值的顺序,你总是可以舍弃常数,但是我认为map方法更干净。根据while
begin
确实返回了
iterator
,iterator是
const\u iterator
的别名,因为C++11我相信别名是用来实现通用容器接口的,所有容器都有
iterator
const\u iterator
。对于不知道
std::set
的详细信息的模板,这可能会起作用,这是模板代码在任何地方都使用
auto
的一个很好的理由,或者至少是为了限制它不打算修改的引用。如果提问者在其当前具有
Int&
的位置使用
Container::value\u type&
编写一些模板代码,那么该模板不必要地无法为集合实例化。
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) {  
              ^