2014-02-12 99 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