2017-06-06 104 views
0

我一直在閱讀this answer關於使用std::make_move_iterator將元素從std::vector<std::unique_ptr<T>>移動到另一個。它完美的作品:使用std :: make_move_iterator將std :: list <std :: unique_ptr >>插入另一個時出錯

std::vector<std::unique_ptr<int>> c1; 
std::vector<std::unique_ptr<int>> c2; 
c1.push_back(std::unique_ptr<int>(new int)); 
c2.insert(c2.end(), std::make_move_iterator(c1.begin()), std::make_move_iterator(c1.end())); 

現在我試着去改變它使用一個不同的容器(std::list):

std::list<std::unique_ptr<int>> c1; 
std::list<std::unique_ptr<int>> c2; 
c1.push_back(std::unique_ptr<int>(new int)); 
c2.insert(c2.end(), std::make_move_iterator(c1.begin()), std::make_move_iterator(c1.end())); 

但是編譯失敗:

錯誤C2248:「STD: :unique_ptr < _Ty> :: unique_ptr':無法訪問在類中聲明的私有成員'std :: unique_ptr < _Ty>'

但是,它的工作,如果列表中包含其他對象(如std::string):

std::list<std::string> s1; 
std::list<std::string> s2; 
s2.insert(s2.end(), std::make_move_iterator(s1.begin()), std::make_move_iterator(s1.end())); 

現在,如果我用another answer從同樣的問題,它採用std::back_inserterstd::move,它與兩個std::vectorstd::list

std::list<std::unique_ptr<int>> c1; 
std::list<std::unique_ptr<int>> c2; 
c1.push_back(std::unique_ptr<int>(new int)); 
std::move(c1.begin(), c1.end(), std::back_inserter(c2)); 

據我所知,這種解決方案基本上移動每個項目時單獨回到插入第二個容器時。

我的問題是,爲什麼在的std::unique_ptrstd::list不起作用使用std::make_move_iterator但它與std::vector如果列表元素是一個不同類型的呢?

注:我使用Visual Studio 2010中

+1

VS2 010是古老的。 [適用於我](http://rextester.com/AYXH86359)與VS2017。 –

+0

有趣......謝謝! – cbuchart

+0

我不知道它是否有任何解決方法?我有問題中提到的另一個解決方案,但我將無法從VS 2010遷移一段時間 – cbuchart

回答

0

的核心問題是,Visual Studio 2010中的執行std::list::insert不支持移動語義。在內部,std::list::insert調用一個名爲_Insert方法,它被聲明爲在VS 2010中如下:

void _Insert(const_iterator _Where, const _Ty& _Val) 

在VS 2017年(不檢查其它版本),它調用相同的方法,但它被聲明爲:

void _Insert(_Unchecked_const_iterator _Where, _Valty&&... _Val) 

如圖所示,VS 2017使用右值引用,因此在插入時調用移動構造函數std::unique_ptr。另一方面,VS 2010使用一個左值引用,所以在某些時候調用了複製構造函數,它被聲明爲私有的,生成編譯錯誤std::unique_ptr


結論

在VS 2010中就沒有辦法使用基於std::make_move_iterator因爲如何std::list::insert實現的解決方案。對於追加std::list<std::unique_ptr<T>>到另一個選項包括:

  • 使用back_inserter

    std::move(c1.begin(), c1.end(), std::back_inserter(c2)); 
    
  • 使用std::list::splice(信貸@T.C.),因爲它可以用返回的列表可以直接使用,這是非常有用的通過功能:

    c2.splice(c2.end(), c1); 
    
相關問題