std::unordered_map::extract 引用/指针失效

10

针对新的C++17 std::unordered_map::extract函数,文档说明如下:

仅将节点提取出来不会使未删除元素的相对顺序发生变化,并且仅会使到被提取的元素的迭代器失效。提取元素后,对该元素的指针和引用仍然有效,但是在元素由节点句柄拥有时无法使用:如果将元素插入容器中,则可以再次使用。

当然,extract函数会使提取的元素所属的容器中的迭代器失效。但是文档关于引用和指针的描述很奇怪 - 它说这些保持有效,但不能使用直到重新插入(可能是另一个)容器中 - 在这种情况下,它们将保留其值(?)。

问题:我的用例是在提取元素后检查该元素,即进行一次erase-examine-discardForGood操作,只需进行一次哈希查找。 extract函数似乎非常适合这种情况,但文档表明我不能使用node_type来检查元素。请问我的理解是否正确?

2个回答

7
您可以理解为extract(和相应的insert)“神奇地”改变了受影响的映射元素的类型:当元素由地图拥有时,它具有类型std :: pair<const key_type,mapped_type>,但当元素由节点句柄拥有时,它具有类型std :: pair<key_type,mapped_type>(因此您可以更改键的值)。

因此,如果在元素由地图拥有时获取对元素的引用/指针,则在提取元素之后重新插入之前无法使用该引用/指针,否则会违反严格别名规则。

但是,在提取后获得的引用/指针是完全可以使用的。


很有见地,谢谢... 如果持有指向直接 value_type 的指针,您的评论是否适用?(而不是 pair<>)。 - haelix

6

是的,这就是文本所说的。

乍一看,这似乎是一个相当任意的限制,但我相信有一些良好的、神秘的原因。

话虽如此,句柄本身具有成员函数value()/key()/mapped(),可能对您有价值(!)。

节点句柄是一种移动类型,它拥有并提供对存储在节点中的元素(value_type)的访问,并提供对元素的键部分(key_type)和映射部分(mapped_type)的非const访问。(参考)


句子:该句柄本身具有成员函数。是的,我决定使用node_type::value(),但是我被文档搞糊涂了。我正在持有从映射中指向value_type的指针,据说在节点分离时不应解引用。现在,当节点仍然附加时,来自该指针的值要么等于&nodeHandle.value(),要么不等于...如果你明白我的意思的话。 - haelix
简而言之,当删除映射元素时,我需要清除其他数据结构中指向map::value_type的指针。我认为可以通过extract提取该节点并在这些结构中查找&nodeHandle.value()来安全地执行此操作。 - haelix
@haelix 哦,痛哉,只要“可用”意味着我所想的意思,那应该是可以工作的。 - Lightness Races in Orbit
3
汽车引擎下面发生了一些不正当的事情,将 pair<const Key, Value> 变成了 pair<Key, Value>(无需移动或复制)。这由实现来确保其有效性,但是这种魔法不保证可移植性。当类型转换时,语言律师们会变得非常兴奋。需要担心编译器优化、缓存失效以及其他问题。只要您比较指针而不解除引用已缓存的指针,我认为您就不会出错。 - Howard Hinnant
1
是的,就是那个。实际位置很不可能改变(为什么会改回去呢?),但涉及到的复杂性来自于C++不是一个裸机编程语言,而是一个具有复杂类型系统和诸如此类的抽象。有人可能会认为这本身就是一个巨大的抽象泄漏,但这就是当“用户空间”通过库实现时,可能成为语言特性的情况。至少我们得到了这个特性吧。 - Lightness Races in Orbit
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接