为啥允许 std::unordered_map::rehash() 使迭代器无效?
Posted
技术标签:
【中文标题】为啥允许 std::unordered_map::rehash() 使迭代器无效?【英文标题】:Why std::unordered_map::rehash() is allowed to invalidate iterators?为什么允许 std::unordered_map::rehash() 使迭代器无效? 【发布时间】:2020-10-03 20:24:03 【问题描述】:Visual Studio (2015) 实现不会使任何迭代器失效(rehash()
重新排序内部 std::list
,保持所有迭代器有效)。
是否有其他实现使迭代器无效(并获得更好的性能,即使具有相同的复杂性)?
在 std::unordered_map::rehash()
上使迭代器无效有时会限制开发人员(例如,我正在尝试仅使用 std::unordered_map
实现 LRU 缓存:节点的值具有容器的迭代器)。但是使迭代器无效的可能性是否允许更好地实现std::unordered_map::rehash()
?
【问题讨论】:
几乎所有标准容器类在变异操作中使迭代器无效,std::list
是个例外。
请注意,重新散列只会使迭代器无效,而不是指针或对元素的引用。由于重新散列改变了内部链表的顺序,这是有道理的。如果元素的顺序在此操作中间发生变化,您将如何定义迭代元素的操作?
@Ilyan 我现在明白你的意思了。恐怕用std::unordered_map
实现LRU 缓存效率不高。我现在检查了有关此问题的多个问题,但所有建议的解决方案都在从缓存中逐出元素时触发了查找。这可能是您想要避免的。你需要的是一个指向unrodered_map
node 的指针,它在重新散列后不会失效。但未提供此功能。
顺便说一句,您可以通过保留桶数来避免重新散列吗?设置为所需的 LRU 缓存大小加上设置最大负载因子?
如果 Microsoft STL 保证在重新散列后迭代器不会失效,我想这就是实现问题。不知道内部细节,但请注意,通常每个解决方案都有利有弊,因此 MS 实现可能会由于此设计决策而存在一些缺点。
【参考方案1】:
感谢@DanielLangr 的上述讨论,
我认为,此要求附带std::unordered_map::[const_]iterator
定义为LegacyForwardIterator
(而不是LegacyBidirectionalIterator
)。如果不使 rehash()
中的迭代器失效(可能,end()
除外),使用内部 std::forward_list
或类似的(而不是 VS 的 std::list
)具有更好内存占用的实现是不可能的。
sizeof(std::unordered_map::[const_]iterator)
,但定义std::unordered_map
要求绝对是正确的原样,并将所有这些考虑因素留给实施者。
【讨论】:
以上是关于为啥允许 std::unordered_map::rehash() 使迭代器无效?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我不能增加 std::unordered_map 迭代器?
为啥`std::unordered_map::erase(key_type const&)`返回删除元素的数量?
gcc std::unordered_map 实现速度慢吗?如果是这样 - 为啥?