地图移动插入是否保证元素是否被移动?

11
C++中的标准“map”容器允许您插入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?
显然,在上述情况下,答案是“是”,因为移动已经在创建对时发生。但现在假设我想更新现有值,但仍保留值是否已存在的信息(因此我不能只说m[1] = std::move(x);)。在这种情况下,“不移动”对象是否可能?
我在GCC中发现以下内容有效[更新:适用于GCC 4.6,不适用于GCC 4.8]:
auto it = m.insert(std::pair<const int, T &&>(1, std::move(x)));

但这个有保证不会移动吗?

你总是可以先使用 find()... :) - Nim
1
@Nim:一般来说那不够高效。如果有的话,最好使用带提示插入的 lower_bound 函数。我知道这个函数。 - Kerrek SB
4
尝试使用 m.emplace_back(1, std::move(x)); - Xeo
@Xeo: 一直在努力寻找支持它的编译器 :-) 你有任何保证吗? - Kerrek SB
@Xeo:对于关联容器,使用emplace而不是emplace_back :-) - Kerrek SB
显示剩余2条评论
1个回答

16
尽管std::move实际上并不执行任何移动操作,std::make_pair也是如此,但std::make_pair会将其参数转发到std::pair构造函数中,该构造函数从这些参数初始化其两个值成员。因此,在std::map有机会执行任何操作之前,移动是在那个时刻执行的。因此,是的,你最终会因没有好的理由而得到一个“损坏”的移动。
你应该能够利用emplace(以跳过对pair的构造)。来自表102的效果:“仅当容器中没有与t的键等效的元素时,使用std::forward<Args>(args)...构造一个T对象t插入。”很明显,库在这一点上仍然在“转发”,因此它是前移的,在你的情况下不应进行任何emplacement,因此整个表达式应该是有效的空操作。
However,GCC 4.8.0中的libstdc++在这方面似乎存在一个错误:emplace会在内部树上调用_M_emplace_unique,它将参数转发到_M_create_node,然后将参数转发到allocator_traits<_Node_allocator>::construct,最后将参数转发到_S_construct,然后将参数转发到__a.construct。使用默认分配器时,__a.constructstd::allocator<std::pair<const _Key, _Tp> >::construct,这正是您试图避免的对成对构造函数的调用……所有这些都发生在_M_emplace_unique中的冲突检查之前。

可以说在这方面标准存在歧义,但我认为这是违反意图的。然而,clang v3.4 with libc++ 也表现出了这种行为, Visual Studio 2012也是如此。因此,如果我的标准解释是正确的,那么所有三个主流工具链都会失败。

我想他们都决定“当且仅当”适用于插入操作,而不是插入构建操作。

我已经在std-discussion上发布了一个问题,旨在促进从表102到权威回答这个问题的改进。


3
老实说,我认为在标准中加入一个指出这一点的“注释”会比较明智,但是目前我认为我们可以推断出上述内容。 - Lightness Races in Orbit
嗯...你能用unique pointer让它工作吗?插入的拼写是怎样的--m.emplace(1, std::move(ptr))?我在GCC 4.8.2中无法使其工作,即指针最终仍为空。 - Kerrek SB
鉴于标准文本,似乎是这样的?关联插入支持在最近进展缓慢(请看我的编辑:GCC 4.6和4.8之间的pair-with-reference代码也有所不同),因此这很可能存在漏洞。 - Kerrek SB
所以,问题归根结底是没有单独的“emplace(key, valueargs...)”方法? - Kerrek SB
@KerrekSB:嘿,我猜是吧。我仍然认为可以通过检查rvalue ref本身来检查密钥,而无需实际移动。但是我对pack expansion(或者说实话,rvalue refs本身)了解不够,无法确定这是否是一个美好的梦想... - Lightness Races in Orbit
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接