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

发布于 2024-07-21 10:56:17 字数 102 浏览 1 评论 0原文

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

If I change an element of an std::set, for example, through an iterator, I know it is not "reinserted" or "resorted", but is there any mention of if it triggers undefined behavior? For example, I would imagine insertions would screw up. Is there any mention of specifically what happens?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦醒灬来后我 2024-07-28 10:56:17

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

使用STL容器类集
用于数据的存储和检索
来自其中值的集合
所包含的元素是唯一的
并作为关键值
数据自动存储到其中
订购了。 a 中某个元素的值
设置不能直接更改。
相反,您必须删除旧值
并插入具有新值的元素。

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

You should not edit the values stored in the set directly. I copied this from MSDN documentation which is somewhat authoritative:

The STL container class set is used
for the storage and retrieval of data
from a collection in which the values
of the elements contained are unique
and serve as the key values according
to which the data is automatically
ordered. The value of an element in a
set may not be changed directly.
Instead, you must delete old values
and insert elements with new values.

Why this is is pretty easy to understand. The set implementation will have no way of knowing you have modified the value behind its back. The normal implementation is a red-black tree. Having changed the value, the position in the tree for that instance will be wrong. You would expect to see all manner of wrong behaviour, such as exists queries returning the wrong result on account of the search going down the wrong branch of the tree.

在风中等你 2024-07-28 10:56:17

确切的答案取决于平台,但作为一般规则,“密钥”(您放入集合中的内容或地图的第一种类型)应该是“不可变的”。 简单来说就是不应该修改,也不存在自动重新插入的情况。

更准确地说,用于比较键的成员变量不得修改。

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,这显然没有排序...糟糕...
不过,当您想要修改不参与运算符的数据时,这种行为还是很有用的。。 但你最好知道自己在做什么:这就是你因过于灵活而付出的代价。

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

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

现在也在 gcc 上编译,相同的输出:100 25 40
但至少,这样做可能会让您想知道发生了什么,然后转到堆栈溢出并查看此线程:-)

The precise answer is platform dependant but as a general rule, a "key" (the stuff you put in a set or the first type of a map) is suppose to be "immutable". To put it simply, that should not be modified, and there is no such thing as automatic re-insertion.

More precisely, the member variables used for to compare the key must not be modified.

Windows vc compiler is quite flexible (tested with VC8) and this code compile:

// 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;

The output is 100 25 40, which is obviously not sorted... Bad...
Still, such behavior is useful when you want to modify data not participating in the operator <. But you better know what you're doing: that's the price you get for being too flexible.

Some might prefer gcc behavior (tested with 3.4.4) which gives the error "assignment of read-only location". You can work around it with a const_cast:

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

That's now compiling on gcc as well, same output: 100 25 40.
But at least, doing so will probably makes you wonder what's happening, then go to stack overflow and see this thread :-)

满地尘埃落定 2024-07-28 10:56:17

你不可以做这个; 它们是const。 set 没有任何方法可以检测到您对内部元素进行的更改,因此您无法这样做。 相反,您必须删除并重新插入该元素。 如果您使用复制成本高昂的元素,则可能必须改用指针和自定义比较器(或改用支持右值引用的 C++1x 编译器,这将使事情变得更好)。

You cannot do this; they are const. There exists no method by which the set can detect you making a change to the internal element, and as a result you cannot do so. Instead, you have to remove and reinsert the element. If you are using elements that are expensive to copy, you may have to switch to using pointers and custom comparators (or switch to a C++1x compiler that supports rvalue references, which would make things a whole lot nicer).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文