rlb*_*ond 12 c++ collections stl set
如果我通过迭代器更改std :: set的元素,我知道它不是"重新插入"或"求助",但有没有提到它是否触发了未定义的行为?例如,我认为插入会搞砸.有没有具体提到会发生什么?
180*_*ION 24
您不应直接编辑存储在集合中的值.我从MSDN文档中复制了这个,这有点权威:
STL容器类集用于存储和检索集合中的数据,其中包含的元素的值是唯一的,并且用作根据其自动排序数据的键值.集合中元素的值可能不会直接更改.相反,您必须删除旧值并使用新值插入元素.
为什么这很容易理解.该set实施将无法知道你已经修改了其背后的价值的方式.正常实现是红黑树.更改了值后,该实例树中的位置将是错误的.您可能希望看到各种错误行为,例如由于exists搜索沿着树的错误分支返回错误结果.
小智 5
确切的答案取决于平台,但作为一般规则,"键"(放在集合中的东西或第一种类型的映射)被认为是"不可变的".简而言之,不应修改它,也不要自动重新插入.
更准确地说,不能修改用于比较密钥的成员变量.
Windows vc编译器非常灵活(使用VC8测试)并且此代码编译:
// creation
std::set<int> toto;
toto.insert(4);
toto.insert(40);
toto.insert(25);
// bad modif
(*toto.begin())=100;
// output
for(std::set<int>::iterator it = toto.begin(); it != toto.end(); ++it)
{
std::cout<<*it<<" ";
}
std::cout<<std::endl;
Run Code Online (Sandbox Code Playgroud)
输出是100 25 40,显然没有排序......糟糕......但是,当你想修改不参与运算符的数据时,这种行为很有用.但是你最好知道你在做什么:这是你过于灵活的价格.
有些人可能更喜欢gcc行为(使用3.4.4测试),这会产生错误"只读位置的分配".您可以使用const_cast解决它:
const_cast<int&>(*toto.begin())=100;
Run Code Online (Sandbox Code Playgroud)
现在也在gcc上进行编译,输出相同:100 25 40.但至少,这样做可能会让你想知道发生了什么,然后去堆栈溢出并看到这个线程:-)