将其移动到地图后访问一对

时间:2013-07-09 15:27:53

标签: c++ c++11 map move-semantics std-pair

如果我将一对移动到地图中,但由于该密钥已经存在而插入失败,我可以安全地使用该对吗?

//objects available: map, pair

auto insert_pair = map.insert(std::move(pair));

if (!insert_pair.second)
{
  //can I safely access pair here?
}

这是否已在标准中记录?

4 个答案:

答案 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>

然而,在处理正式语言的规范时,“非常非常合理”不是一个有效的论据。在这种情况下,从正式的角度来看,没有什么能阻止实现执行以下操作:

  1. 首先从你的参数构造一对tmp(这意味着你不能在函数返回后对你的参数状态做出假设);
  2. 检查地图中是否已存在该键;
  3. 如果没有,请进行必要的内务处理,将tmp插入容器中。
  4. 甚至:

    1. 检查地图中是否存在密钥;
    2. 如果是这样,请从您的参数中插入一个移动构造的新元素;
    3. 如果没有,请从您的参数中移动构造一个新对象,并对其执行任何操作。
    4. 上述第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将返回对地图中已存在的对的引用。

文档在这里: http://www.cplusplus.com/reference/map/map/insert/