简体   繁体   English

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

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

If I move a pair into a map, but the insert failed because the key already exists, can I safely use the pair afterwards? 如果我将一对移动到地图中,但由于密钥已经存在而插入失败,我可以安全地使用该对吗?

//objects available: map, pair

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

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

Has this been documented in the standard? 这是否已在标准中记录?

For how non-sense this may seem (read below), given the current state of the specification you cannot make any assumption on the state of the argument after the function call returns. 对于看起来如何无意义(如下所示),给定规范的当前状态,您不能在函数调用返回后对参数的状态做出任何假设。

To see why, let's first point out that the insert() member function is defined in terms of emplace() (see 23.4.4.4/1): 为了解原因,让我们首先指出insert()成员函数是根据emplace emplace()定义的(见23.4.4.4/1):

The first form is equivalent to return emplace(std::forward<P>(x)) . 第一种形式相当于return emplace(std::forward<P>(x)) [...] [...]

The post-conditions of emplace() are in turn specified as (see § 23.2.4, Table 102): emplace()的后置条件又被指定为(见第23.2.4节,表102):

Inserts a value_type object t constructed with std::forward<Args>(args)... if and only if there is no element in the container with key equivalent to the key of t . 插入一个value_type对象t与构造std::forward<Args>(args)...当且仅当存在与等价键的键容器中没有元件t The bool component of the returned pair is true if and only if the insertion takes place, and the iterator component of the pair points to the element with key equivalent to the key of t . 当且仅当插入发生时,返回对的bool组件才为true ,并且该对的迭代器组件指向具有等效于t键的键的元素。

The sentence in bold from the above quote (emphasis is mine) says that the pair that will become an element of the map if the key is not already present will be move-constructed directly from the rvalue pair you supply. 上面引用的粗体句子(强调是我的)表示如果键不存在将成为地图元素的对将直接从你提供的右值对移动构造。

This would make it very very reasonable to deduce that implementations will first have to check if the key is present and, only if not, move-construct the new map's element from the your pair. 这将使得非常合理地推断出实现首先必须检查密钥是否存在,并且仅在不存在的情况下,从您的对中移动构造新映射的元素。

However, "very very reasonable" is not a valid argument when dealing with the specification of a formal language. 但是,在处理正式语言的规范时,“非常非常合理”不是一个有效的论据。 In this case, from the formal viewpoint there is nothing that prevents an implementation from doing the following: 在这种情况下,从正式的角度来看,没有什么能阻止实现执行以下操作:

  1. First move-construct a pair tmp from your argument (which would mean you can't make assumptions on the state of your argument after the function returns); 首先移动 - 从你的参数构造一对tmp (这意味着你不能在函数返回后对你的参数的状态做出假设);
  2. Check if the key is already present in the map; 检查密钥是否已存在于地图中;
  3. If not, do the necessary housekeeping to insert tmp into the container. 如果没有,请进行必要的管理以将tmp插入容器中。

Or even: 甚至:

  1. Check if the key is present in the map; 检查地图中是否存在密钥;
  2. If so, insert a new element move-constructed from your argument; 如果是这样,请从您的参数中插入一个移动构造的新元素;
  3. If not, move-construct a new object from your argument and do nothing with it. 如果没有,请从您的参数中移动构造一个新对象,并对其执行任何操作。

Point 3 above is absolutely meaningless, but it is not formally forbidden. 上面的第3点绝对毫无意义,但并未正式禁止。 Mind the phrasing: 记住措辞:

Inserts a value_type object t constructed with std::forward<Args>(args)... if and only if there is no element in the container with key equivalent to the key of t . 插入一个value_type对象t与构造std::forward<Args>(args)...当且仅当存在与等价键的键容器中没有元件t

This only says that if there is no element in the container with key equivalent to the key of t , no object move-constructed from t will be inserted into the map - but, for how stupid this may sound, it does not say that no object at all shall be move-constructed from t : as long as it does not get inserted into the map, this is allowed. 这只说明如果容器中没有元素,其键与t键相同,则不会将从t构造的对象移植到地图中 - 但是,对于这听起来多么愚蠢,它并不是说没有对象根本不应该从t构造:只要它没有插入到地图中,就允许这样做。

This said, since the Standard does not explicitly constrain implementations in this respect, you cannot make assumptions on whether or not your argument was moved from. 这就是说,既然标准没有明确约束这方面的实现,你就不能假设你的论证是否被移除了。 Consequently, you cannot make assumptions on the state your pair will be in when the function call returns (per paragraph 17.6.5.15). 因此,当函数调用返回时,您不能对您的对将处于的状态进行假设(根据第17.6.5.15段)。

If I can let a personal opinion sneak in, though, I believe this is a defect. 但是,如果我可以透露个人意见,我相信这是一个缺陷。

I couldn't find anything concrete, but as far as the standard goes regarding types defined by the STL (eg, pair): 我找不到具体的东西,但就STL定义的类型(例如,对)标准而言:

17.6.5.15: Unless otherwise specified, such moved-from objects shall be placed in a valid but unspecified state. 17.6.5.15:除非另有规定,否则此类移动物体应处于有效但未指明的状态。

Without satisfying that "otherwise specified", which I haven't been able to find for a "failed" map::insert, this would mean that by the standard you could not use the pair. 如果不满足“另外指定”,我无法找到“失败的”map :: insert,这将意味着按照标准你不能使用该对。 In reality, based on sensical implementations, I imagine that the pair would remain unchanged, but relying on this would fall into the realm of undefined compiler/stl-specific behavior. 实际上,基于敏感实现,我认为该对将保持不变,但依赖于此将落入未定义的编译器/特定于stl的行为领域。

From Table 102 in section 23.2.4 Associative containers of the c++11 standard (draft n3337) the following is stated (for expression a_uniq.insert(t) which applies in this case): 表102中的第23.2.4节c ++ 11标准(草案n3337)的关联容器中,陈述了以下内容(对于在这种情况下适用的表达式a_uniq.insert(t) ):

Requires: If t is a non-const rvalue expression, value_type shall be MoveInsertable into X; 要求:如果t是非const rvalue表达式,则value_type应为MoveInsertable为X; otherwise, value_type shall be CopyInsertable into X. Effects: Inserts t if and only if there is no element in the container with key equivalent to the key of t. 否则,value_type应为CopyInsertable到X.效果:当且仅当容器中没有元素且密钥等于t的键时才插入t。 The bool component of the returned pair is true if and only if the insertion takes place, and the iterator component of the pair points to the element with key equivalent to the key of t. 当且仅当插入发生时,返回对的bool组件才为真,并且该对的迭代器组件指向具有等效于t键的键的元素。

It makes no statement on any effect on t if an insertion does not occur (I am unsure whether this falls under unspecified or implementation-defined behaviour). 如果没有发生插入,它不会对t任何影响做出声明(我不确定这是否属于未指定实现定义的行为)。 I was unable to locate any other clause that provided further clarification so it appears the standard does not supply a definitive answer. 我无法找到任何其他提供进一步澄清的条款,因此标准似乎没有提供明确的答案。 It would be possible to rewrite the posted code to only call insert() if the pair is not present or just use the returned iterator. 如果该对不存在或仅使用返回的迭代器,则可以重写已发布的代码以仅调用insert()

Yes, you can use the pair. 是的,你可以使用这对。 Insert will return a reference to the pair that already exists in the map. Insert将返回对地图中已存在的对的引用。

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

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

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