I read a beautiful article on the move semantics in C++11. This article is written in a very intuitive way. The example class in the article is given below.
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;
};
Clearly in the above move constructor implementation, the movement doesn't happen for the the embedded element _metadata. To facilitate this the trick is to use the std::move() method like this.
ArrayWrapper (ArrayWrapper&& other)
: _p_vals( other._p_vals )
, _metadata( std::move( other._metadata ) )
{
other._p_vals = NULL;
}
So far, so good.
The standard says:
§5 (C++11 §5[expr]/6):
[ Note: An expression is an xvalue if it is:
the result of calling a function, whether implicitly or explicitly, whose return type is an rvalue reference to object type,
a cast to an rvalue reference to object type,
a class member access expression designating a non-static data member of non-reference type in which the object expression is an xvalue, or
a
.*pointer-to-member expression in which the first operand is an xvalue and the second operand is a pointer to data member.
My question:
Now, the variable other in the move constructor is an xvalue (am I right?). Then according to the last rule above, other._metadata should also be an xvalue. And hence the compiler can implicitely use the move constructor of _metadata's class. So, no need to std::move here.
What am I missing?