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

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

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

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

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

【问题讨论】:

    标签: c++ c++17 unordered-map erase


    【解决方案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<>)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    • 2021-09-26
    • 1970-01-01
    • 2019-01-15
    • 2021-12-23
    • 1970-01-01
    相关资源
    最近更新 更多