如果我将一对移动到地图中,但由于密钥已经存在而导致插入失败,我可以安全地使用该对吗?
//objects available: map, pair
auto insert_pair = map.insert(std::move(pair));
if (!insert_pair.second)
{
//can I safely access pair here?
}
这是否已在标准中记录?
如果我将一对移动到地图中,但由于密钥已经存在而导致插入失败,我可以安全地使用该对吗?
//objects available: map, pair
auto insert_pair = map.insert(std::move(pair));
if (!insert_pair.second)
{
//can I safely access pair here?
}
这是否已在标准中记录?
对于看起来如何无意义(如下所示),给定规范的当前状态,您不能在函数调用返回后对参数的状态做出任何假设。
要明白为什么,让我们先指出一下 insert()
成员函数是根据定义的 emplace()
(见23.4.4.4/1):
第一种形式相当于
return emplace(std::forward<P>(x))
。 [...]
后期条件 emplace()
反过来又指定为(参见第23.2.4节,表102):
插入一个
value_type
目的t
用。构造std::forward<Args>(args)...
当且仅当没有 容器中的元素 键相当于键t
。 该bool
的组成部分 返回的对是true
如果和 只有插入需要 地方和迭代器 该对的组成部分 用键来元素 相当于的关键t
。
从上面引用的粗体句子(强调是我的)说如果键不存在将成为地图元素的那对将被移动构造 直 从您提供的右值对。
这样就可以了 非常合理 推断出实现首先必须检查密钥是否存在,并且只有在不存在的情况下,从您的对中移动构造新映射的元素。
但是,在处理正式语言的规范时,“非常非常合理”不是一个有效的论据。在这种情况下,从正式的角度来看,没有什么能阻止实现执行以下操作:
tmp
从你的参数(这意味着你不能在函数返回后对你的参数的状态做出假设);tmp
进入容器。甚至:
上面的第3点绝对毫无意义,但并未正式禁止。记住措辞:
插入一个
value_type
目的t
用。构造std::forward<Args>(args)...
当且仅当没有 容器中的元素 键相当于键t
。
这只表示如果容器中没有元素,其键等效于键 t
,没有移动构造的对象 t
将被插入到地图中 - 但是,对于这听起来多么愚蠢,它并没有这么说 完全没有任何对象 应由...构成 t
:只要它没有插入到地图中,就允许这样做。
这就是说,既然标准没有明确约束这方面的实现,你就不能假设你的论证是否被移除了。因此,当函数调用返回时,您不能对您的对将处于的状态进行假设(根据第17.6.5.15段)。
但是,如果我可以透露个人意见,我相信这是一个缺陷。
我找不到具体的东西,但就STL定义的类型标准而言(例如,对):
17.6.5.15:除非另有规定,否则此类移动物体 应置于有效但未指明的状态。
如果不满足“另外指定”,我无法找到“失败的”map :: insert,这将意味着按照标准你不能使用该对。实际上,基于敏感实现,我认为该对将保持不变,但依赖于此将落入未定义的编译器/特定于stl的行为的领域。
从 表102 在部分 23.2.4关联容器 在c ++ 11标准(草案n3337)中,陈述了以下内容(表达式) a_uniq.insert(t)
在这种情况下适用):
要求:如果t是非const rvalue表达式,则value_type应为MoveInsertable为X;否则,value_type应为CopyInsertable到X.效果:当且仅当容器中没有元素且密钥等于t的键时才插入t。当且仅当插入发生时,返回对的bool组件才为真,并且该对的迭代器组件指向具有等效于t键的键的元素。
它没有任何关于任何影响的声明 t
如果没有插入(我不确定这是否属于 不明 要么 实现定义 行为)。我无法找到任何其他提供进一步澄清的条款,因此标准似乎没有提供明确的答案。可以将已发布的代码重写为仅调用 insert()
如果该对不存在或只是使用返回的迭代器。
是的,你可以使用这对。 Insert将返回对地图中已存在的对的引用。