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?