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

Posted

技术标签:

【中文标题】std::unordered_map::extract 引用/指针失效【英文标题】:std::unordered_map::extract references/pointers invalidation 【发布时间】:2018-10-10 11:24:55 【问题描述】:

对于新的 C++17 std::unordered_map::extract 函数,文档说:

提取节点只会使提取的迭代器无效 元素,并保留非元素的相对顺序 抹去。指向提取元素的指针和引用仍然有效, 但不能在元素由节点句柄拥有时使用:它们 如果元素被插入到容器中,则变得可用。

当然,extract 使提取的迭代器无效(这是容器的东西,元素已从中删除)。但是文档对引用和指针很奇怪——它说这些仍然有效,但在重新插入(可能是另一个)容器之前不能使用——在这种情况下它们将保留它们的值(?)。

问题:我的用例是在提取后检查一个元素,即只使用一次哈希查找进行擦除-检查-丢弃操作。 extract 函数似乎非常适合这个,但是文档表明我不能使用 node_type 来检查元素。我的理解正确吗?

【问题讨论】:

【参考方案1】:

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

乍一看,这似乎是一个相当武断的限制,但我敢肯定它有一些好的,如果是神秘的,原因。

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

节点句柄是一个只移动类型,它拥有并提供对存储在节点中的元素(value_type)的访问,并提供对元素的键部分(key_type)和映射部分的非常量访问元素(映射类型)。 (ref)

【讨论】:

句柄本身有成员函数 是的,我决定使用node_type::value(),但我被文档弄糊涂了。我 am 持有指向地图中value_types 的指针,据推测我不应该在节点分离时取消引用。现在,当节点仍然连接时,这样的指针要么等于&nodeHandle.value(),要么不等于......如果你明白我的意思。 简而言之 - 当地图元素被删除时,我需要从其他数据结构中清除一些指向 map::value_type 的指针。我认为通过extract-ing 该节点并在这些结构中寻找&nodeHandle.value() 这样做是安全的。 @haelix 哦,哎哟,只要“可用”是我认为的意思,那应该可以工作 @haelix 幕后有一些手脚将pair<const Key, Value> 变成pair<Key, Value>(没有移动或复制)。由实现来确保它有效,但不能保证这种魔法是可移植的。当类型双关出现时,语言律师会变得相当兴奋。有编译器优化要担心,缓存失效要担心,我不记得还有什么。只要您在比较指针,而不是取消引用缓存的指针,我认为您就在界限之内。 是的,那个。实际位置不太可能改变(为什么会变回来?)但是涉及的复杂性来自 C++ 不是裸机编程语言,而是具有复杂类型系统的抽象和等等等等。有人可能会争辩说,这本身就是一个巨大的抽象泄漏,但是当库在“用户空间”中实现潜在的语言功能时,就会发生这种情况。至少我们得到了我猜想的功能。【参考方案2】:

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

因此,如果您在该元素归地图所有时获取该元素的引用/指针,则在提取该元素之后重新插入该元素之前,您不能使用该引用/指针,否则您将违反严格的别名规则。

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

【讨论】:

那是很好的洞察力,谢谢...如果直接持有指向value_type 的指针,您是否表示适用? (不是pair<>)。

以上是关于std::unordered_map::extract 引用/指针失效的主要内容,如果未能解决你的问题,请参考以下文章