修改std :: set的元素会发生什么?

时间:2009-05-26 04:37:03

标签: c++ stl collections set

如果我通过迭代器更改std :: set的元素,我知道它不是“重新插入”或“使用”,但有没有提到它是否触发了未定义的行为?例如,我认为插入会搞砸。有没有具体提到会发生什么?

3 个答案:

答案 0 :(得分:24)

您不应直接编辑存储在集合中的值。我从MSDN文档中复制了这一点,这有点权威:

  

使用STL容器类集   用于存储和检索数据   从一个集合中的价值观   所包含的元素是独一无二的   并作为关键值   数据是自动的   订购。 a中元素的值   设置可能无法直接更改。   相反,您必须删除旧值   并使用新值插入元素。

为什么这很容易理解。 set实现无法知道您已修改其背后的值。正常实现是红黑树。更改了值后,该实例树中的位置将是错误的。您可能希望看到各种错误的行为,例如exists查询返回错误的结果,因为搜索沿着树的错误分支返回。

答案 1 :(得分: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;

输出 100 25 40 ,显然没有排序......糟糕... 当您想要修改未参与运算符&lt; 的数据时,此类行为仍然很有用。但你最好知道自己在做什么:这就是因为过于灵活而得到的代价。

有些人可能更喜欢gcc行为(使用3.4.4测试),这会产生错误“只读位置的分配”。你可以使用const_cast解决它:

const_cast<int&>(*toto.begin())=100;

现在正在编译gcc,输出相同: 100 25 40 。 但至少,这样做可能会让你想知道发生了什么,然后去堆栈溢出并看到这个线程: - )

答案 2 :(得分:4)

你不能这样做;他们是constset没有方法可以检测到您对内部元素进行了更改,因此您无法执行此操作。相反,您必须删除并重新插入元素。如果使用复制昂贵的元素,则可能必须切换到使用指针和自定义比较器(或切换到支持rvalue引用的C ++ 1x编译器,这会使事情变得更好)。

相关问题