I have been trying to write a class that cannot be copied but can be moved, and that cannot be created except with named constructors. I achieved my goal with namedConstructor3
below. However, I do not understand why namedConstructor2
failed.
struct A
{
int a;
//static A && namedConstructor1( int a_A )
//{
// A d_A( a_A );
// return d_A; // cannot convert from A to A&&
//}
static A && namedConstructor2( int a_A )
{
wcout << L"Named constructor 2\n";
A d_A( a_A );
return move( d_A );
}
static A namedConstructor3( int a_A )
{
wcout << L"Named constructor 3\n";
A d_A( a_A );
return move( d_A );
}
A( A && a_RHS ) : a( a_RHS.a )
{
a_RHS.a = 0;
wcout << L"\tMoved: a = " << a << endl;
}
~A()
{
wcout << L"\tObliterated: a = " << a << endl;
a = -a;
}
A( const A & ) = delete;
A & operator =( const A & ) = delete;
protected:
A( int a_A = 0 ) : a( a_A )
{
wcout << L"\tCreated: a = " << a << endl;
}
};
int main()
{
A d_A2 = A::namedConstructor2( 2 );
A d_A3 = A::namedConstructor3( 3 );
wcout << "Going out of scope\n";
return 0;
}
The output is
Named constructor 2
Created: a = 2
Obliterated: a = 2
Moved: a = -2
Named constructor 3
Created: a = 3
Moved: a = 3
Obliterated: a = 0
Going out of scope
Obliterated: a = 3
Obliterated: a = -2
Questions:
Why is the destructor called before the move constructor in
namedConstructor2
as evidenced by the 3rd and 4th lines of the output?Why is the destroyed data still available to the moved constructor (as evidenced by the 4th line of the output)?
Isn't
namedConstructor2
"more natural" thannamedConstructor3
in the sense that the signature ofstd::move
leads me to think that the return value ofstd::move
has "two &&"?
template< class T >
typename std::remove_reference<T>::type&& move( T&& t )
Compiled with VS2013u4.
Edit
Deduplicator's answer satisfies me. This edit is for completeness sake. The answer and the comments suggested that namedConstructor3
was "sub-optimal". I added
static A namedConstructor4( int a_A )
{
wcout << L"Named constructor 4\n";
A d_A( a_A );
return d_A;
}
to the class and A d_A4 = A::namedConstructor4( 4 );
to the main
function. The new output (when compiled in release mode, not in debug mode) shows that the optimal case does not even move the object:
Named constructor 2
Created: a = 2
Obliterated: a = 2
Moved: a = -2
Named constructor 3
Created: a = 3
Moved: a = 3
Obliterated: a = 0
Named constructor 4
Created: a = 4
Going out of scope
Obliterated: a = 4
Obliterated: a = 3
Obliterated: a = -2