我可以移动 - 将std :: map的内容分配到另一个std :: map中吗?

时间:2014-02-12 10:15:17

标签: c++ c++11 move-semantics

是否可以通过使用移动语义将临时std :: map temp的内容插入到另一个std :: map m中,这样就不会复制临时值,而是重用?

让我们说一个人:

std::map<int, Data> temp;
std::map<int, Data> m;

将值从temp复制到m的一种方法是:

m.insert(temp.begin(),temp.end());

我如何将<{1}}元素移动到temp而不是复制?

3 个答案:

答案 0 :(得分:20)

提示: 首先阅读更新!

当前的C ++ 11标准和C ++ 14草案不提供启用此功能的成员函数。正如lavr建议你仍然可以写

m.insert(make_move_iterator(begin(temp)),
         make_move_iterator(end  (temp)));

从源容器移动到目标容器中。但是,容器节点和键都不会被移动。这需要内存分配(至少用于在目标映射中创建新节点)。源容器中的元素数量将保持不变。复制背后的原因很简单:std::map的值类型为std::pair<const Key,T>。从const Key移动本质上是复制密钥(除非有人超载了Key构造函数,该构造函数需要const Key &&,我无法想到这是一个充分的理由。

如果您需要将数据从一个容器移动到另一个容器,可以考虑使用std::list而不是std::map。它有一个member function splice,可以在恒定的时间内将元素从一个列表移动到另一个列表。

<强>更新

自C ++ 17以来,函数std::map::merge()基本上将一个std::map的所有元素放入另一个std::map而不移动或复制实际元素,而是通过重新指定内部指针只要。它与自{+ C} 98以来存在的std::list::splice()非常相似。

所以你可以写

m.merge( temp );

实现目标。这比将所有元素从一个容器复制或移动到另一个容器更有效。

但要注意!冲突的密钥将无法解决:对于重合的密钥,将不会执行任何操作。

答案 1 :(得分:7)

没试过,但我认为std::move_iterator应该有所帮助:

 using it = std::map<int, Data>::iterator;
 using mv = std::move_iterator <it>;

 m.insert(mv(temp.begin()),mv(temp.end()));

答案 2 :(得分:3)

我不认为这是可能的。对于其他容器,我会建议std::move_iterator适配器,但这不起作用,因为地图的键是const。

换句话说,您无法从地图中逐个移出元素,因为这可能会更改地图不允许的键。

并且无法从一张地图批量移动到另一张地图。列表支持拼接,但我担心树木不会。