繁体   English   中英

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

[英]Accessing a pair after moving it into a map

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

//objects available: map, pair

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

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

这是否已在标准中记录?

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

为了解原因,让我们首先指出insert()成员函数是根据emplace 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键的键的元素。

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

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

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

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

甚至:

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

上面的第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将返回对地图中已存在的对的引用。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM