I\'m confused about when a move constructor gets called vs a copy constructor. I\'ve read the following sources:
Move constructor is not getting called in C++0x
Remember that copy elision could occur. If you disable it by passing the -fno-elide-constructors
flag to the compiler your constructor might get executed.
You can read about it here: https://www.geeksforgeeks.org/copy-elision-in-c/
First of all, your copy constructor is broken. Both the copied from and copied to objects will point to the same Array
and will both try to delete[]
it when they go out of scope, resulting in undefined behavior. To fix it, make a copy of the array.
a::a(const a& Old): Array(new int[5])
{
for( size_t i = 0; i < 5; ++i ) {
Array[i] = Old.Array[i];
}
}
Now, move assignment is not being performed as you want it to be, because both assignment statements are assigning from lvalues, instead of using rvalues. For moves to be performed, you must be moving from an rvalue, or it must be a context where an lvalue can be considered to be an rvalue (such as the return statement of a function).
To get the desired effect use std::move to create an rvalue reference.
A=C; // A will now contain a copy of C
B=std::move(C); // Calls the move assignment operator
A move constructor is called:
std::move(something)
std::forward<T>(something)
and T
is not an lvalue reference type (useful in template programming for "perfect forwarding")This is not a complete list. Note that an "object initializer" can be a function argument, if the parameter has a class type (not reference).
a RetByValue() {
a obj;
return obj; // Might call move ctor, or no ctor.
}
void TakeByValue(a);
int main() {
a a1;
a a2 = a1; // copy ctor
a a3 = std::move(a1); // move ctor
TakeByValue(std::move(a2)); // Might call move ctor, or no ctor.
a a4 = RetByValue(); // Might call move ctor, or no ctor.
a1 = RetByValue(); // Calls move assignment, a::operator=(a&&)
}