如果我有一个未命名的unique_ptr对象,该对象持有对象Foo,为什么将其添加到矢量中时不删除该对象?
示例:
vec.push_back(std::unique_ptr<Foo>(new Foo())));
为什么不删除Foo?我曾尝试实现此功能,但似乎无法解决,因为我删除了析构函数中的对象。
答案 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中忽略它):
unique_ptr<Foo>
。其值为prvalue(一种右值)。push_back
method被调用。由于参数是在1中创建的临时参数,因此将调用第二个(右值引用)重载。这意味着该值已被移动到向量中。unique_ptr
's move constructor(该页面上的第五个重载),这创建了一个unique_ptr<Foo>
,管理与1中的临时项相同的Foo
,并使该临时项改为按住nullptr
。 nullptr
,所以它没有任何特别的作用。