为什么取消引用指向 std::set 的提取节点的指针是未定义的行为?

布兰德林戈

我在我公司做了一个关于关联容器的新(C++17)拼接接口的闪电演讲。我演示了std::set::extract,然后被问到迭代器和指向提取元素的指针会发生什么。他们让我措手不及,我无法回答这个问题,但在谈话结束后立即查了一下。

[associative.reqmts]当前标准草案中的21.2.6.10内容如下:

extract成员仅无效迭代器被删除的元素; 指向已删除元素的指针和引用仍然有效。但是,在元素归 a 所有时通过此类指针和引用访问元素node_­type是未定义的行为。node_­type如果元素被成功插入,则在元素拥有时获得的元素的引用和指针将失效。

(提案P0083R3已包含此措辞)

现在强调的部分真的让我感到不安。我理解有效但不可取消引用的指针 ( nullptr) 或迭代器(结束迭代器)的概念。我找到了David Vandevoorde对有效指针“定义”,并了解到还有有效但不可取消引用的指针不是nullptr. (即一个指针经过现有对象)

有了这一切,我对发生的事情的心理模型如下:

  1. 检索指向集合中元素的指针,因此该指针是有效的。取消引用该指针已定义并产生对集合中元素的访问。
  2. 现在从集合中提取相同的元素。从概念上讲,元素不会被复制、移动或以其他方式更改,它的关联节点只是从set管理其数据的内部树中删除剩余的树可能需要重新平衡。返回node_handle的拥有孤立树节点的所有权。

按照标准,在 1) 中检索到的指针仍然有效并且不能被 更改extract,因此这也支持这种心理模型。然而,在这个模型中,没有理由解除对指针的引用会突然未定义。因此,在coliru 上使用g++似乎可以按我的预期工作(这不打算作为任何形式的证明)

标准给库实现者的余地似乎不必要地大。我错过了什么?我只看到在提取它们时设置值的常量性被删除,但看不出这会产生什么影响。

同样的推理适用于最后引用的句子中提到的插入情况。

卡莱斯

您的心智模型忽略了这样一个事实:严格来说,删除常量必须是实现定义的。

node_handle必须采取的所有权不同的对象,但通过一些实现定义的魔法,被构造该可变对象弹簧成不存在,具有相同的值,并存储作为原始,const对象。

类似地,当它被插入到一个具有兼容分配器的集合中时,该集合会将node_handleback拥有的可变对象转换为原始的 const 对象。

这是未定义的行为,因为当“它”归 拥有时,const 对象已经不复存在node_handle,但是当它被重新插入时它又重新开始存在。

node_handle如果您具有用户定义的std::pair<const K, V>or 特化,那么这种推理使得从地图中使用的行为成为未定义的行为std::pair<K, V>您不想将实现限制在实现所有这些的“魔术”方式上,因此您可以制作任何会观察“魔术”未定义行为的东西。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

为什么std :: uninitialized_copy通常将迭代器取消引用未初始化的内存,这不是未定义的行为吗?

来自分类Dev

如何在std :: set中存储指向对象的指针(或引用)

来自分类Dev

指向std :: unordered_set中元素的指针/引用

来自分类Dev

如何在std :: set中存储指向对象的指针(或引用)

来自分类Dev

为什么以下各项具有相同的值:指向数组的指针,指向数组的取消引用的指针?

来自分类Dev

具有自定义谓词的std :: unordered_set中的未定义行为

来自分类Dev

指向根的二叉树指针需要被引用和取消引用。为什么?

来自分类Dev

指向根的二叉树指针需要被引用和取消引用。为什么?

来自分类Dev

为什么在这些折叠表达式中使用std :: min是未定义的行为?

来自分类Dev

为什么取消引用指向数组的指针时C程序崩溃?

来自分类Dev

为什么std :: shared_ptr取消引用不会引发空指针异常(或类似的异常)?

来自分类Dev

为什么将功能分配给std :: function会导致未定义的引用?

来自分类Dev

扩展std名称空间被视为未定义行为的原因是什么?

来自分类Dev

为什么允许引用间接指向指针?

来自分类Dev

为什么在std中未定义rand_r?

来自分类Dev

是否取消引用等于nullptr的指针的标准未定义行为?

来自分类Dev

取消引用NULL指针是否被视为未指定或未定义的行为?

来自分类Dev

使用指向typedef固定长度数组的指针执行memcpy时是否需要取消引用?为什么或者为什么不?

来自分类Dev

为什么将指针与未定义的行为进行比较仍然会给出正确的结果?

来自分类Dev

为什么这是未定义的行为?

来自分类Dev

未定义对std :: ios_base :: Init :: Init()的引用

来自分类Dev

取消引用无效的指针但不使用结果是否是C ++中的未定义行为?

来自分类Dev

正在取消引用恒定的未定义行为

来自分类Dev

错误:取消引用未定义的指针值

来自分类Dev

读取指向已删除内存的指针是否存在未定义的行为?

来自分类Dev

为什么将数组作为函数的实际参数发送给期望指向数组的指针的函数需要取消引用两次才能访问该数组?

来自分类Dev

可以使用std :: uintptr_t避免越界指针算术的未定义行为吗?

来自分类Dev

std :: lock_guard导致未定义的行为

来自分类Dev

为什么空指针取消引用也不例外

Related 相关文章

  1. 1

    为什么std :: uninitialized_copy通常将迭代器取消引用未初始化的内存,这不是未定义的行为吗?

  2. 2

    如何在std :: set中存储指向对象的指针(或引用)

  3. 3

    指向std :: unordered_set中元素的指针/引用

  4. 4

    如何在std :: set中存储指向对象的指针(或引用)

  5. 5

    为什么以下各项具有相同的值:指向数组的指针,指向数组的取消引用的指针?

  6. 6

    具有自定义谓词的std :: unordered_set中的未定义行为

  7. 7

    指向根的二叉树指针需要被引用和取消引用。为什么?

  8. 8

    指向根的二叉树指针需要被引用和取消引用。为什么?

  9. 9

    为什么在这些折叠表达式中使用std :: min是未定义的行为?

  10. 10

    为什么取消引用指向数组的指针时C程序崩溃?

  11. 11

    为什么std :: shared_ptr取消引用不会引发空指针异常(或类似的异常)?

  12. 12

    为什么将功能分配给std :: function会导致未定义的引用?

  13. 13

    扩展std名称空间被视为未定义行为的原因是什么?

  14. 14

    为什么允许引用间接指向指针?

  15. 15

    为什么在std中未定义rand_r?

  16. 16

    是否取消引用等于nullptr的指针的标准未定义行为?

  17. 17

    取消引用NULL指针是否被视为未指定或未定义的行为?

  18. 18

    使用指向typedef固定长度数组的指针执行memcpy时是否需要取消引用?为什么或者为什么不?

  19. 19

    为什么将指针与未定义的行为进行比较仍然会给出正确的结果?

  20. 20

    为什么这是未定义的行为?

  21. 21

    未定义对std :: ios_base :: Init :: Init()的引用

  22. 22

    取消引用无效的指针但不使用结果是否是C ++中的未定义行为?

  23. 23

    正在取消引用恒定的未定义行为

  24. 24

    错误:取消引用未定义的指针值

  25. 25

    读取指向已删除内存的指针是否存在未定义的行为?

  26. 26

    为什么将数组作为函数的实际参数发送给期望指向数组的指针的函数需要取消引用两次才能访问该数组?

  27. 27

    可以使用std :: uintptr_t避免越界指针算术的未定义行为吗?

  28. 28

    std :: lock_guard导致未定义的行为

  29. 29

    为什么空指针取消引用也不例外

热门标签

归档