超出范围时,unique_ptr如何不破坏/释放它指向的内存?

时间:2018-07-18 03:21:35

标签: c++

如果我有一个未命名的unique_ptr对象,该对象持有对象Foo,为什么将其添加到矢量中时不删除该对象?

示例:

vec.push_back(std::unique_ptr<Foo>(new Foo())));

为什么不删除Foo?我曾尝试实现此功能,但似乎无法解决,因为我删除了析构函数中的对象。

3 个答案:

答案 0 :(得分:6)

std::vector::push_back的参数是临时的,因此它将作为右值引用传递给push_back。如您在documentation中所见,push_back有两种形式,第二种形式是右值引用。 unique_ptr将被移动到向量中,并且您为参数创建的临时目录将不再拥有内存。

您无法复制std::unique_ptr;如果尝试这样做,则会出现编译错误。但是,完全可以移动唯一的指针。以前的所有者不再拥有它曾经指向的内存。

答案 1 :(得分:3)

在这种情况下,由于要传递临时对象,因此移动重载称为:void std::vector<T>::push_back(T&&)。移动语义允许在不需要昂贵的副本的情况下进行很好的优化。没有它们,push_back将需要复制unique_ptr(实际上unique_ptr的语义是不可能的),您确实会看到析构函数被调用。通过移动语义,向量中的新unique_ptr实际上可以窃取临时内容,并且不会进行复制。有关移动语义的更多说明,请参见here

答案 2 :(得分:2)

之所以发生这种情况,是因为unique_ptr没有副本构造函数,而必须将其移到各处。

这是在C ++ 11或14中发生的情况,忽略了复制/移动省略(由于规则已更改,因此我们不允许在C ++ 17中忽略它):

  1. 您构造了一个临时unique_ptr<Foo>。其值为prvalue(一种右值)。
  2. push_back method被调用。由于参数是在1中创建的临时参数,因此将调用第二个(右值引用)重载。这意味着该值已被移动到向量中。
  3. 引导程序使用unique_ptr's move constructor(该页面上的第五个重载),这创建了一个unique_ptr<Foo>,管理与1中的临时项相同的Foo,并使该临时项改为按住nullptr
  4. 该语句完成,并且需要销毁1.中的临时变量。 Its destructor被调用。因为它拥有nullptr,所以它没有任何特别的作用。