我用美丽的文章阅读了C++11的移动语义,这篇文章是用非常直观的方式写的。本文中的示例类如下所示。
class ArrayWrapper
{
public:
// default constructor produces a moderately sized array
ArrayWrapper ()
: _p_vals( new int[ 64 ] )
, _metadata( 64, "ArrayWrapper" )
{}
ArrayWrapper (int n)
: _p_vals( new int[ n ] )
, _metadata( n, "ArrayWrapper" )
{}
// move constructor
ArrayWrapper (ArrayWrapper&& other)
: _p_vals( other._p_vals )
, _metadata( other._metadata )
{
other._p_vals = NULL;
}
// copy constructor
ArrayWrapper (const ArrayWrapper& other)
: _p_vals( new int[ other._metadata.getSize() ] )
, _metadata( other._metadata )
{
for ( int i = 0; i < _metadata.getSize(); ++i )
{
_p_vals[ i ] = other._p_vals[ i ];
}
}
~ArrayWrapper ()
{
delete [] _p_vals;
}
private:
int *_p_vals;
MetaData _metadata;
};显然,在上面的move构造函数实现中,嵌入式元素_metadata不会发生移动。为了方便这一点,诀窍是像这样使用std::move()方法。
ArrayWrapper (ArrayWrapper&& other)
: _p_vals( other._p_vals )
, _metadata( std::move( other._metadata ) )
{
other._p_vals = NULL;
} 到现在为止还好。
标准上说:
第5条(C++11§5 /6):
[注:表达式如果为x值,则为:
.*指针到成员表达式,其中第一个操作数是一个xvalue,第二个操作数是指向数据成员的指针。我的问题是:
现在,移动构造函数中的变量other是一个xvalue (我说得对吗?)然后,根据上面的最后一条规则,other._metadata也应该是xvalue。因此编译器可以隐含地使用_metadata类的move构造函数,所以这里不需要std::move。
我遗漏了什么?
发布于 2012-07-30 15:37:17
你的假设不是真的。构造函数的参数是xvalue,它允许绑定rvalue-引用,但是一旦rvalue-引用被绑定,在构造函数中,它不再是xvalue,而是lvalue。从概念上讲,调用地的对象正在过期,但在构造函数内部,直到它完成,它不再过期,因为它可以稍后在构造函数块中使用。
ArrayWrapper f();
ArrayWrapper r = f(); // [1]在1中,表达式f()引用了一个临时表达式,它在调用构造函数之后将过期,因此它可以被一个rvalue引用绑定。
ArrayWrapper (ArrayWrapper&& other)
: _p_vals( other._p_vals )
, _metadata( other._metadata ) // [2]
{
other._p_vals = NULL;
std::cout << other._metadata << "\n"; // [3]
} 在构造函数中,other不过期,它将对构造函数的每条指令都是活动的。如果编译器允许在2中移动,那么进一步使用3中的变量将是无效的。您必须显式地告诉编译器,您希望该值现在到期。
发布于 2012-07-30 15:32:25
other是一个L值,因为它是一个变量。命名引用是lvalue,不管它们是什么类型的引用。
https://stackoverflow.com/questions/11724592
复制相似问题