2015-04-26 96 views
3

我想將unique_ptr<Foo>vector<unique_ptr<Foo>>中移出。想想我的代碼:如何將unique_ptr移出載體<unique_ptr <Foo>>?

#include <vector> 
#include <memory> 
#include <iostream> 

using namespace std; 

class Foo { 
public: 
    int x; 
    Foo(int x): x(x) {}; 
    ~Foo() { 
    cout << "Destroy of id: " << x << "\n"; 
    x = -1; 
    }; 
}; 

int main(int argc, char *argv[]) { 
    auto foos = vector<unique_ptr<Foo>>(); 
    foos.push_back(unique_ptr<Foo>(new Foo(100))); 
    foos.push_back(unique_ptr<Foo>(new Foo(101))); 
    foos.push_back(unique_ptr<Foo>(new Foo(102))); 

    // Print all 
    cout << "Vector size: " << foos.size() << "\n"; 
    for (auto i = foos.begin(); i != foos.end(); ++i) { 
    cout << (*i)->x << "\n"; 
    } 

    // Move Foo(100) out of the vector 
    { 
    auto local = move(foos.at(0)); 
    cout << "Removed element: " << local->x << "\n"; 
    } 

    // Print all! Fine right? 
    cout << "Vector size: " << foos.size() << "\n"; 
    for (auto i = foos.begin(); i != foos.end(); ++i) { 
    cout << (*i)->x << "\n"; 
    } 

    return 0; 
} 

我預計這將產生:

Vector size: 3 
100 
101 
102 
Removed element: 100 
Destroy of id: 100 
Vector size: 2 
101 
102 

但是,相反,我得到這樣的結果:

Vector size: 3 
100 
101 
102 
Removed element: 100 
Destroy of id: 100 
Vector size: 3 
Segmentation fault: 11 

爲什麼我的矢量大小還是3,爲什麼我是否收到分段錯誤?我怎樣才能得到我想要的結果?

+3

矢量沒有壞掉。您可以在解除引用之前檢查unique_ptr。但你選擇不要。 – juanchopanza

+0

@juanchopanza我已經清楚地發佈了我想要的輸出結果。你還想要什麼? – Doug

+0

根據你所說的,你不想移動任何東西,你只是想複製 – AndyG

回答

4

讓我們來簡化你的問題到:

vector<unique_ptr<Foo>> foos; 
foos.push_back(unique_ptr<Foo>(new Foo(100))); 
auto local = std::move(foos[0]); 
std::cout << foos[0]->x << '\n'; 

通過移動foos[0]創建local後,foos[0]不再具有指針的所有權。它是空的。取消引用它成爲未定義的行爲,在您的情況下表現爲分段錯誤。該vector是完美的「完整」在這一點上,它包含一個空unique_ptr,並且是等同的狀態:

vector<unique_ptr<Foo>> foos(1); 

您應該簡單地檢查unique_ptr非關聯化之前擁有一個指針:

if (foos[0]) { 
    // we wouldn't get here 
    std::cout << foos[0]->x << '\n'; 
} 

另外,既然你想強制你的vector只包含有效指針的不變量,作爲你的移動操作的一部分,你應該只是erase那個元素:

auto local = std::move(foos[0]); 
foos.erase(foos.begin()); 
// now foos is empty 
+0

嘿,謝謝你解釋清楚。 – Doug

相關問題