使用 unordered_set/unordered_multiset 的迭代器失效

Iterator invalidation with unordered_set/unordered_multiset

提问人:QuickDzen 提问时间:11/12/2023 最后编辑:wohlstadQuickDzen 更新时间:11/13/2023 访问量:128

问:

我知道在插入元素时可能会使迭代器失效:unordered_set

“如果发生重新散列(由于插入),所有迭代器都将失效。”

很明显,因为我们有带桶的哈希表,但为什么不使迭代器失效呢?
我认为的实现与(带有存储桶的哈希表)的实现几乎相同。
unordered_multisetunordered_setunordered_multiset

C++ STL 哈希表 序集 无序 多集

评论

0赞 273K 11/12/2023
为什么unordered_multiset不会使迭代器失效?你能添加对这个声明的引用吗?
2赞 Yksisarvinen 11/12/2023
我检查的第一个函数,在 multiset 中重新散列也意味着迭代器失效:en.cppreference.com/w/cpp/container/unordered_multiset/insert
0赞 wohlstad 12/1/2023
如果某个答案解决了您的问题@QuickDzen您可以单击“✔”将其标记为已接受的答案。您还可以对任何有用的答案投赞成票(请参阅此处:当有人回答我的问题时,我该怎么办?

答:

1赞 wohlstad 11/12/2023 #1

实际上,在这方面,和 之间没有区别std::unordered_setstd::unordered_multiset

正如您在 unordered_multiset::insert 中所看到的,它包含与 unordered_set::insert 完全相同的注释

如果发生重新散列(由于插入),则所有迭代器都将失效。

顺便说一句 - 在没有重新散列的情况下,它们也是相同的:

否则(不重新散列),迭代器不会失效。

请注意,这并不意味着两个容器在使迭代器失效时总是表现相同 - 因为实现有一定的自由度(调整桶计数等,这可能会影响重新散列 - 请参阅下面的 @TonyDelroy 评论)。

评论

0赞 Tony Delroy 11/25/2023
“控制是否发生重新散列的策略可以不同” - 策略/逻辑由 C++ 标准一成不变 - 重新散列仅在超出时发生,这需要在构造函数中设置为 1.0,尽管客户端代码可以更改它。虽然发生重新哈希的策略/逻辑无法更改,但实现可以自由调整存储桶计数和增长,以馈入重新哈希策略计算。load_factormax_load_factor
1赞 wohlstad 11/25/2023
@TonyDelroy我改写了。随意再次改写以使其更准确。无论如何,这只是一个笔记。主要答案是,与OP所建议的不同,在这方面没有区别。
0赞 Shrawns 11/13/2023 #2

在 C++ 标准库中,插入期间迭代器失效的 unordered_set 和 unordered_multiset 的行为可能看起来很相似,但在处理重复项的方式上存在关键差异。

unordered_set:

在unordered_set中,每个元素都是唯一的,如果超过负载因子阈值,插入操作可能会导致重新散列。 重新哈希涉及更改哈希表中的存储桶数量,这可能会使迭代器失效,因为元素可能会移动到新位置。 unordered_multiset:

In an unordered_multiset, duplicate elements are allowed. When you insert an element, the insert operation adds it to the appropriate bucket without considering rehashing due to load factors. Since the number of buckets doesn't change during regular insertions (only when the container is resized), iterators are generally not invalidated during insertions.存储桶中的现有元素不会受到插入新元素的影响,迭代器仍然可以指向正确的存储桶。 总之,主要区别在于对重复项的处理。在unordered_multiset中,新元素的插入不会像unordered_set中那样触发重新散列,因此,迭代器在常规插入期间不太可能失效。检查您正在使用的 C++ 实现的特定文档或标准始终很重要,因为详细信息可能因不同的标准库实现而异。

是的,有区别,可能没有那么大,但它仍然是一个非常有效的@wohlstad

评论

0赞 wohlstad 11/13/2023
我没有声称容器是相同的。当然有区别。但它们与 OP 关于迭代器中的迭代器是否因重新散列而失效的问题无关。OP 引用了规范并问“为什么unordered_multiset不使迭代器失效?”答案是(正如我所写的)——如果发生重新散列,它们实际上是无效的——就像 .容器可能会以不同的方式重新散列,这一事实与问题无关。unordered_multisetunordered_set
0赞 wohlstad 11/13/2023
无论如何,我添加了关于重新散列策略可能存在的差异的澄清。
0赞 wohlstad 11/13/2023
另请注意,您提到的一些细节是特定于实现的,据我所知,规范并不严格要求(即使它是一个常见的实现)。
1赞 Tony Delroy 11/25/2023
“插入操作将其添加到适当的存储桶中,而不考虑由于负载因素而重新散列”——我认为这是完全错误的。C++ 标准 [unord.req] 对所有无序容器说:“当元素添加到无序关联容器中时,存储桶的数量会自动增加,因此每个存储桶的平均元素数保持在边界以下。重新散列会使迭代器失效“ - 没有关于将重复键视为一个元素的内容(本质上是无意义的)。任何支持该说法的参考?unordered_multimap