2015-04-26 58 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

相关问题