我在我公司做了一个关于关联容器的新(C++17)拼接接口的闪电演讲。我演示了std::set::extract
,然后被问到迭代器和指向提取元素的指针会发生什么。他们让我措手不及,我无法回答这个问题,但在谈话结束后立即查了一下。
[associative.reqmts]当前标准草案中的21.2.6.10内容如下:
的
extract
成员仅无效迭代器被删除的元素; 指向已删除元素的指针和引用仍然有效。但是,在元素归 a 所有时通过此类指针和引用访问元素node_type
是未定义的行为。node_type
如果元素被成功插入,则在元素拥有时获得的元素的引用和指针将失效。
(提案P0083R3已包含此措辞)
现在强调的部分真的让我感到不安。我理解有效但不可取消引用的指针 ( nullptr
) 或迭代器(结束迭代器)的概念。我找到了David Vandevoorde对有效指针的“定义”,并了解到还有有效但不可取消引用的指针不是nullptr
. (即一个指针经过现有对象)
有了这一切,我对发生的事情的心理模型如下:
set
管理其数据的内部树中删除。剩余的树可能需要重新平衡。返回node_handle
的拥有孤立树节点的所有权。按照标准,在 1) 中检索到的指针仍然有效并且不能被 更改extract
,因此这也支持这种心理模型。然而,在这个模型中,没有理由解除对指针的引用会突然未定义。因此,在coliru 上使用g++似乎可以按我的预期工作。(这不打算作为任何形式的证明)
标准给库实现者的余地似乎不必要地大。我错过了什么?我只看到在提取它们时设置值的常量性被删除,但看不出这会产生什么影响。
同样的推理适用于最后引用的句子中提到的插入情况。
您的心智模型忽略了这样一个事实:严格来说,删除常量必须是实现定义的。
在node_handle
必须采取的所有权不同的对象,但通过一些实现定义的魔法,被构造该可变对象弹簧成不存在,具有相同的值,并存储作为原始,const对象。
类似地,当它被插入到一个具有兼容分配器的集合中时,该集合会将node_handle
back拥有的可变对象转换为原始的 const 对象。
这是未定义的行为,因为当“它”归 拥有时,const 对象已经不复存在node_handle
,但是当它被重新插入时它又重新开始存在。
node_handle
如果您具有用户定义的std::pair<const K, V>
or 特化,那么这种推理使得从地图中使用的行为成为未定义的行为std::pair<K, V>
。您不想将实现限制在实现所有这些的“魔术”方式上,因此您可以制作任何会观察“魔术”未定义行为的东西。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句