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

rog*_*mes 11 c++ map move-semantics c++11 std-pair

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

//objects available: map, pair

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

if (!insert_pair.second)
{
  //can I safely access pair here?
}
Run Code Online (Sandbox Code Playgroud)

这是否已在标准中记录?

And*_*owl 7

对于看起来如何无意义(如下所示),给定规范的当前状态,您不能在函数调用返回后对参数的状态做出任何假设.

为了解原因,让我们首先指出insert()成员函数是根据emplace()(见23.4.4.4/1)定义的:

第一种形式相当于return emplace(std::forward<P>(x)).[...]

后置条件emplace()又指定为(见表23第23.2.4节):

插入一个使用value_typetstd::forward<Args>(args)... if 构造 对象, 并且仅当容器中没有元素时才使用等效键的键t.bool返回对的组件是true当且仅当插入发生时,并且该对的迭代器组件指向具有等效于键的键的元素t.

上面引用的粗体句子(强调是我的)表示如果键不存在将成为地图元素的那一对将直接从你提供的右值对中移动构造.

这将使得非常合理地推断出实现首先必须检查密钥是否存在,并且仅在不存在的情况下,从您的对中移动构造新映射的元素.

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

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

甚至:

  1. 检查地图中是否存在密钥;
  2. 如果是这样,请从您的参数中插入一个移动构造的新元素;
  3. 如果没有,请从您的参数中移动构造一个新对象,并对其执行任何操作.

上面的第3点绝对毫无意义,但并未正式禁止.记住措辞:

插入一个使用 if 构造的value_type 对象t, std::forward<Args>(args)...并且仅当容器中没有元素时才使用等效键的键t.

这只说明如果容器中没有元素的键与等效键相同t,则不t会将任何移动构造的对象插入到地图中 - 但是,对于这听起来多么愚蠢,它并没有说明没有对象所有都是移动构造的t:只要它没有插入地图,这是允许的.

这就是说,既然标准没有明确约束这方面的实现,你就不能假设你的论证是否被移除了.因此,当函数调用返回时,您不能对您的对将处于的状态进行假设(根据第17.6.5.15段).

但是,如果我可以透露个人意见,我相信这是一个缺陷.