除非将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
?
答案 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