map move-insertion是否保证元素是否被移动?

Ker*_* SB 11 c++ move-semantics c++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)));
Run Code Online (Sandbox Code Playgroud)

问题是当元素已经存在时会发生什么,即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)));
Run Code Online (Sandbox Code Playgroud)

但这是否保证不动?

Lig*_*ica 16

虽然std::move实际上并不执行任何动作,也不认为std::make_pair,std::make_pair它的参数转发到std::pair构造函数,它初始化它的两个价值成员的论点.

因此,在std::map有机会做任何事情之前,此时就会执行此移动.所以,是的,你没有充分的理由最终得到了"破碎"的举动.

你应该能够利用emplace(为了跳过这对结构).从表102:

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

显然,图书馆此时仍然"转发",所以它是预先移动的,在你的情况下,不会发生任何安置,所以整个表达应该是一个有效的无操作.

但是,来自GCC 4.8.0的libstdc ++ 似乎在这方面存在一个错误:在内部树上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.

可以说这个标准在这方面是模棱两可的,但我称之为违背意图.然后,使用libc ++的 clang v3.4 也会出现这种行为,Visual Studio 2012也是如此.因此,如果我的标准解释是正确的,那么所有三个主流工具链都会失败.

我猜他们都决定将"if if only only"应用于插入,而不是插入构造.

我已经发布了一个关于std讨论的问题,旨在激发对表102的通过的改进,以便一劳永逸地权威地回答这个问题.

  • 老实说,我认为标准中的_Note_指出这一点在这里是明智的,但我认为我们现在可以推断出上述情况. (3认同)