2013-11-22 80 views
3

我注意到,當包含類型包含unique_ptr時,不可能刪除矢量的元素。如何在包含對象包含unique_ptr時刪除矢量的元素?

例如這個類:

class Bar 
    { 
     std::unique_ptr<int> pointerTest; 

     Bar(Bar &bar) {}; 

    public: 
     Bar() { pointerTest = std::unique_ptr<int>(new int); } 
     Bar(Bar &&bar) { this->pointerTest = move(bar.pointerTest); } 

     void testFunc() { pointerTest.release(); } 
    }; 

這不會與這種用法工作:

int main() 
    { 
     vector<Bar> test123; 

     Bar foo; 
     test123.push_back(move(foo)); 
     test123.erase(test123.begin()); 
    } 

    //Error 1 error C2280: 'std::unique_ptr<int,std::default_delete<_Ty>> &std::unique_ptr<_Ty,std::default_delete<_Ty>>::operator =(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function c:\program files (x86)\microsoft visual studio 12.0\vc\include\xmemory0 611 1 testing 

的代碼將工作時,你只調用對象的方法,而不是擦除:

for (auto &item : test123) 
    item.testFunc(); 

爲什麼我不能在矢量上使用擦除,我該如何解決這個問題?

+2

FWIW,你的代碼在g ++ 4.6下編譯。 – user4815162342

+0

我可以通過刪除不必要的移動構造函數和奇怪的副本構造函數來解決GCC 4.8上的問題。我不知道問題到底是什麼,或者是否會爲您的編譯器解決問題。 –

+0

奇怪的是,我無法在visual studio 2013上編譯此文件,無論是否帶有複製和移動構造函數。 @Mike Seymour關於這些構造函數的連線是什麼? – Dagob

回答

3

問題是您的班級沒有正確遵守三/五的規則。您可以定義一個副本並移動構造函數,但不能移動賦值運算符。這意味着不會生成移動賦值運算符,並且在分配時始終使用默認的複製賦值運算符。但是,由於您的課程擁有不可複製的成員,因此默認的複製分配操作符被定義爲已刪除,因此您在使用時會出錯。

並且它被調用,因爲從矢量中移除元素會導致矢量的所有後續元素的移位(即賦值)。這通常是一個移動賦值,但是由於在你的類中沒有定義(而不是自動生成),複製賦值被調用 - 並且失敗。

我看到你使用的是Visual Studio,所以移動構造/移動賦值操作符不會自動生成(VS不支持這部分標準)。因此,要以VS兼容的方式解決此問題,請定義一個移動賦值運算符。在你處理拷貝構造函數的時候刪除拷貝構造函數可能是一個好主意 - 這個類看起來像是一個非拷貝類的主要例子。

1

從克++ 4.8.1該錯誤消息是很清楚:

garbage.cpp:9:11:注意: '酒吧&酒吧::運算符=(const的酒吧&)' 被 隱式聲明如刪除,因爲「酒吧」宣稱此舉 構造函數或移動賦值操作符

通過增加移動運營商的問題就解決了:

class Bar 
{ 
     std::unique_ptr<int> pointerTest; 

     Bar(const Bar &); 

public: 
     Bar() { pointerTest = std::unique_ptr<int>(new int); } 
     Bar(Bar &&bar) : pointerTest(move(bar.pointerTest)) {} 
     Bar& operator=(Bar&& bar){ pointerTest = std::move(bar.pointerTest); return *this;} 

     void testFunc() { pointerTest.release(); } 
};