地图移动插入是否保证元素被移动或不移动? [英] Does map move-insertion guarantee that elements are or are not moved from?

查看:150
本文介绍了地图移动插入是否保证元素被移动或不移动?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C ++中的标准地图容器允许您插入右值:

The standard "map" containers in C++ allow you to insert an rvalue:

T x;

std::map<int, T> m;

// m[1];  // populate "1"

auto it = m.insert(std::make_pair(1, std::move(x)));

问题是当元素已经存在时会发生什么,即 it-> ; second == false 。元素 x 是否已被移出?例如,如果它是一个唯一的指针, x 已被重置为null?

The question is what happens when the element already exists, i.e. it->second == false. Has the element x already been "moved-from"? For instance, if it is a unique pointer, will x have been reset to null?

上述情况是是,因为移动从已经在创建对的点发生。但是现在我想更新现有的值,但仍然保留该值是否已经存在的信息(所以我不能只说 m [1] = std :: move(x) ; )。

Patently the answer in the above case is "yes", because the moving-from happens already at the point of creating the pair. But suppose now I want to update the existing value, but still retain the information of whether the value already existed or not (so I can't just say m[1] = std::move(x);). Is it possible to "not move from" the object in that case?

我在GCC发现以下工作[更新:在GCC 4.6中工作,不是在GCC 4.8中工作]:

I discovered in GCC that the following works [Update: works in GCC 4.6, does not work in GCC 4.8]:

auto it = m.insert(std::pair<const int, T &&>(1, std::move(x)));

但是这是不能移动的?

推荐答案

虽然 std :: move 实际上不执行任何移动,也不会 std :: make_pair , std :: make_pair 将其参数转发到 std :: pair 构造函数

Though std::move does not actually perform any move, and neither does std::make_pair, std::make_pair forwards its arguments to the std::pair constructor, which initialises its two value members from those arguments.

这样,在 std :: map 有机会做任何事情。

As such, the move is performed at that point, before the std::map has a chance to do anything. So, yes, you end up with a "broken" move for no good reason.

你应该能够利用 emplace

You should be able to take advantage of emplace (in order to skip the pair construction). From Table 102:


效果:插入 T 对象 如果且仅当容器中没有带键的元素时,用 std :: forward< Args>(args)... t 的键。

Effects: Inserts a T 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.

很明显,转发在这一点上,所以它的预移动,在你的情况下,不会发生,所以整个表达式应该是一个有效的无效操作。

Clearly, the library is still "forwarding" at this point so it's pre-move, and in your case no emplace shall take place so the entire expression ought to be an effective no-op.

libstdc ++ 来自 GCC 4.8.0似乎有错误在这方面: emplace 调用 _M_emplace_unique 在内部树,它将参数转发到 _M_create_node ,它将参数转发到 allocator_traits< _Node_allocator> :: construct ,将参数转发到 _S_construct ,它将参数转发到 __ a.construct 其中使用默认分配器, std :: allocator< std :: pair< const _Key,_Tp& > :: construct ,这是您尝试避免的对构造函数...在 _M_emplace_unique 中的碰撞检查之前。

However, libstdc++ from GCC 4.8.0 appears to have a bug in this regard: emplace invokes _M_emplace_unique on the internal tree, which forwards the arguments to _M_create_node, which forwards the arguments to allocator_traits<_Node_allocator>::construct, which forwards the arguments to _S_construct, which forwards the arguments to __a.construct which, with the default allocator, is std::allocator<std::pair<const _Key, _Tp> >::construct, which is the pair constructor you were trying to avoid... all before the collision check in _M_emplace_unique.

可以声称这个标准在这方面是不明确的,但我认为它违反了意图。然后, clang v3.4与 libc ++ 也显示此行为,如果我的标准解释是正确的,这在所有三个主流工具链上都会失败。

It could be claimed that the standard is ambiguous in this regard, but I'd call it a violation of intent. Then again, clang v3.4 with libc++ exhibits this behaviour too, as does Visual Studio 2012. So if my standard interpretation is correct, this fails on all three of the mainstream toolchains.

我猜他们都决定应用if and only if

I guess they all decided that the "if and only if" applied to the insertion, rather than the insertion and the construction.

我已经在 std-discussion 旨在激发对Table 102授权一次性地回答这个问题。

I have posted a question on std-discussion aiming to provoke an improvement to the passage from Table 102 to authoritatively answer this once and for all.

这篇关于地图移动插入是否保证元素被移动或不移动?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆