我读了一篇关于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;
};
很明显在上面的移动构造函数实现中,嵌入式元素_metadata
没有发生移动。为了方便,需要使用std::move()
方法来解决这个问题。
ArrayWrapper (ArrayWrapper&& other)
: _p_vals( other._p_vals )
, _metadata( std::move( other._metadata ) )
{
other._p_vals = NULL;
}
看起来一切都很顺利。
标准规定:
§5 (C++11 §5[expr]/6):
[ 注意:如果一个表达式是以下情况之一,则它是一个 xvalue:
调用返回对象类型为右值引用的函数的结果,无论是隐式调用还是显式调用,
将表达式转换为对象类型的右值引用,
一个非引用类型的非静态数据成员的类成员访问表达式,其中对象表达式是 xvalue,或者
第一个操作数是 xvalue,第二个操作数是指向数据成员的指针的
.*
成员指针表达式。
我的问题:
现在,在移动构造函数中,变量other
是一个xvalue(我是对的吗?),根据上述最后一条规则,other._metadata
也应该是一个xvalue。因此编译器可以隐式使用_metadata
类的移动构造函数。所以这里不需要std::move
。
我错了哪里?