为什么我需要在移动构造函数的初始化列表中使用std :: move? [英] Why do I need to use std::move in the initialization list of a move-constructor?
问题描述
假设我有一个(微不足道的)类,它是可移动构造的和可移动赋值的但不是可复制构造的或可复制赋值的:
class movable
{
public:
explicit moving(int){}
可移动(可移动&){}
可移动& operator =(movable&&){return * this; }
movable(const moving&)= delete;
movable& operator =(const movable&)= delete;
};
这个工作正常:
movable m1(movable(17));
这当然不行,因为 m1
不是右值:
可移动m2(m1);但是,我可以将
,将其转换为右值引用,使其工作:m1
包含在 code> std :: movemovable m2(std :: move(m1));
到目前为止,还不错。现在,假设我有一个(同样微不足道的)容器类,它包含一个单一的值:
template< typename T&
类容器
{
public:
显式容器(T& value):value_(value){}
private:
T value_;
};
但这不起作用:
container< movable> c(可移动(17));
编译器(我试过clang 4.0和g ++ 4.7.2)抱怨,在
container
的初始化列表中使用movable
的已删除的复制构造函数。再次,在std :: move
中包含value
,使其有效:显式容器(T& value):value_(std :: move(value)){}
但是为什么在这种情况下需要
$ b $这是因为std :: move
?不是value
已经是可移动和&
类型?如何value_(value)
不同于可移动m1(可移动(42))
?value
是一个命名变量,因此是一个左值。解决方案需要
std :: move
才能将其重新转换为右值,因此会导致T $ c $的移动构造函数重载c>匹配。
换句话说:右值引用可以绑定到右值,但它本身不是一个右值。它只是一个参考,在表达式中它是一个左值。从它创建一个右值的表达式的唯一方法是通过转换。
Let's say I have a (trivial) class, which is move-constructible and move-assignable but not copy-constructable or copy-assignable:
class movable { public: explicit movable(int) {} movable(movable&&) {} movable& operator=(movable&&) { return *this; } movable(const movable&) = delete; movable& operator=(const movable&) = delete; };
This works fine:
movable m1(movable(17));
This, of course, does not work, because
m1
is not an rvalue:movable m2(m1);
But, I can wrap
m1
instd::move
, which casts it to an rvalue-reference, to make it work:movable m2(std::move(m1));
So far, so good. Now, let's say I have a (equally trivial) container class, which holds a single value:
template <typename T> class container { public: explicit container(T&& value) : value_(value) {} private: T value_; };
This, however, does not work:
container<movable> c(movable(17));
The compiler (I've tried clang 4.0 and g++ 4.7.2) complains that I'm trying to use
movable
's deleted copy-constructor incontainer
's initialization list. Again, wrappingvalue
instd::move
makes it work:explicit container(T&& value) : value_(std::move(value)) {}
But why is
std::move
needed in this case? Isn'tvalue
already of typemovable&&
? How isvalue_(value)
different frommovable m1(movable(42))
?解决方案That's because
value
is a named variable, and thus an lvalue. Thestd::move
is required to cast it back into an rvalue, so that it will cause move-constructor overload ofT
to match.To say it another way: An rvalue reference can bind to an rvalue, but it is not itself an rvalue. It's just a reference, and in an expression it is an lvalue. The only way to create from it an expression that is an rvalue is by casting.
这篇关于为什么我需要在移动构造函数的初始化列表中使用std :: move?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!