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

Dan*_*Dan 22 c++ smart-pointers stdvector move-semantics

一个unique_ptr不能被推回到一个std::vector,因为它是不可复制的,除非std::move被使用。但是,让我们F使用一个返回a的函数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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

Hol*_*Cat 34

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

create()返回一个临时std::unique_ptr<A>开始,所以move没有必要。


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

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


Rem*_*eau 8

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

void push_back( T&& value );
Run Code Online (Sandbox Code Playgroud)

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

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


Kad*_*mir 6

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

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

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

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