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