Why is this happening? Shouldn't all three statements just call the MyClass(Args& a)
constructor?
For both MyClass c1 = MyClass(a);
and MyClass c2 = a;
, temporary MyClass
will be constructed at first by the constructor MyClass::MyClass(Args& a)
, then used to copy-initialize the object c1
and c2
. The constructed temporaries are rvalues, that means the move-constructor will be selected for the copy initialization.
On the other hand, if I do create the move constructor the program compiles fine and the move constructor is never called!!!
The reason is copy elision; the copy/move operation is omitted here, results in the fact that MyClass::MyClass(Args& a)
is used to initialize the object c1
and c2
directly.
The rule about copy elision changed since C++17. Note that pre-C++17, copy elision is not guaranteed. And for non-guaranteed copy elision, even when the copy/move operation is omitted the copy/move constructor still needs to be present and accessible.
This is an optimization: even when it takes place and the copy-/move-constructor is not called, it still must be present and accessible (as if no optimization happened at all), otherwise the program is ill-formed.
After C++17 your code would work fine. For guaranteed copy elision, copy/move constructor is not required to be present or accessible.
Under the following circumstances, the compilers are required to omit
the copy- and move- construction of class objects even if the
copy/move constructor and the destructor have observable side-effects.
They need not be present or accessible, as the language rules ensure
that no copy/move operation takes place, even conceptually:
In initialization, if the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the
class of the destination, the initializer expression is used to
initialize the destination object:
T x = T(T(T())); // only one call to default constructor of T, to initialize x