2014-02-12 61 views
17

是否可以通过使用移动语义将临时std :: map temp的内容插入到另一个std :: map m中,使得临时值不被复制并重用?我可以移动 - 将std :: map的内容分配到另一个std :: map吗?

比方说,一个有:

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

一个复制值的方式,从tempm是:

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

我怎样才能移动temp元素融入m,而不是复制?

回答

17

提示:先阅读更新!

当前的C++ 11标准和C++ 14草案不提供用于启用此功能的成员函数。作为拉夫尔建议你仍然可以写

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,它可以将元素从一个列表中移动到另一个列表中。

UPDATE:

由于C++ 17有基本上把之一std::map所有元素到另一个std::map无需移动或复制实际的元件的功能std::map::merge(),但仅通过repointing内部指针。这与自C++ 98以来存在的std::list::splice()非常相似。

所以,你可能写

m.merge(temp); 

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

但要小心!冲突的钥匙不会被解决:对于一致的钥匙什么都不会做。

+1

虽然'const key'会在移动这对时被复制,而'temp'会保持相同数量的元素,'T'会st如果'T'是一个像'std :: vector'这样的移动语义的大型结构,这仍然有意义,对吧? – iavr

+0

@lavr的确是的。 –

2

我不认为这是可能的。与其他容器,我会建议std::move_iterator适配器,但这是行不通的,因为地图的关键是常量。

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

而且没有办法只从一张地图批量移动到另一张地图。列表支持剪接,但恐怕树不。

+0

我不太明白,基础类型是''std :: pair '',为什么键会改变?,我只是从temp提取'mapped_type'并把它移到''m''? – Gabriel

+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())); 
+0

Whewhew ....感谢从我身边 - 不知道这些存在... –

+0

我也不知道:-) – Gabriel

+0

我很确定这不会因为上述原因而工作:/ Library /开发人员/ CommandLineTools/usr/bin /../include/C++/v1/迭代器:959:14:错误: 无法从类型为'const value_type'的左值转换(又名'const std :: __ 1 :: basic_string ' )到右值引用类型 '参考'(又名 “的std :: __ 1 :: basic_string的 &&');类型不兼容 返回的static_cast (* __ⅰ); ^ ~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~ – rossb83