将std :: unique_ptr推回std :: vector时,编译器不会失败

时间:2019-07-07 20:37:44

标签: c++ smart-pointers stdvector move-semantics

除非将unique_ptr不可复制,否则无法将其std::vector推回std::move中。但是,假设F是一个返回unique_ptr的函数,则允许操作std::vector::push_back(F())。下面是一个示例:

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

class A {
  public:
    int f() { return _f + 10; }

  private:
    int _f = 20;
};

std::unique_ptr<A> create() { return std::unique_ptr<A>(new A); }


int main() {
  std::unique_ptr<A> p1(new A());

  std::vector< std::unique_ptr<A> > v;

  v.push_back(p1); // (1) This fails, should use std::move

  v.push_back(create()); // (2) This doesn't fail, should use std::move?

  return 0;
}
允许使用

(2),但不允许使用(1)。这是因为返回的值被隐式地移动了吗?

(2)中,实际上是否需要使用std::move

4 个答案:

答案 0 :(得分:34)

std::move(X)本质上是指“在这里,将X视为一个临时对象”。

create()返回一个临时std::unique_ptr<A>开头,因此move是不必要的。


如果您想了解更多信息,请查看value categories。您的编译器使用值类别来确定表达式是否引用临时对象(“ rvalue”)或否(“ lvalue”)。

p1是一个左值,而create()是一个右值。

答案 1 :(得分:8)

std::vector::push_back()的重载将右值引用作为输入:

void push_back( T&& value );

create()的返回值是一个未命名的临时值,即右值,因此可以按原样传递给push_back(),而无需在其上使用std::move()

std::move()仅在传递命名变量(即左值,期望右值)时才需要。

答案 2 :(得分:5)

使用C ++ 11,我们获得了移动构造函数和右值语义。

std :: move(X)只是对将X转换为X &&的右值的强制转换。比移动ctor接管工作,然后移动构造函数通常“窃取”参数所持有的资源。 unique_ptr有一个移动ctor。

函数返回值已经是一个右值(除非函数返回左值引用(如注释中的@HolyBlackCat所示)),它将触发移动ctor而不需要任何额外的强制转换。而且由于move ctor是为unique_ptr定义的,因此它将进行编译。

v.push_back(p1);失败的原因还在于:您尝试使用左值调用复制构造函数,但失败,因为unique_ptr没有复制ctor。

答案 3 :(得分:2)

值得一提的是,由于编译器能够移动未显式移动的对象(NRVO),因此它也可以工作

.ckpt