Reputation: 2108
Code :
#include <iostream>
class A {
public:
A() {
}
A(const A& a) {
std::cout << "Copy constructor" << std::endl;
}
A(A&& a) {
std::cout << "Move constructor" << std::endl;
}
};
int main()
{
{//case 1
A b = A(A());
}
std::cout << std::endl;
{// case 2
A a;
A b = A(a);
}
std::cout << std::endl;
{//case 3
A a;
A b = A(std::move(a));
}
}
Output (with -O3 compilation flag) :
#case 1
#nothing printed
#case 2
Copy constructor
#case 3
Move constructor
In case 2, why is the copy constructor called even with maximum optimization level (-O3) ? I was expecting the compiler to detect that the variable 'a' is like being temporary (because used only for the construction of 'b') and to rather use the move constructor (like in case 3).
To my knowledge there is at least one case (return value optimization) where the compiler can alter the observable behavior of the program by avoiding the call to a copy constructor which has side effect.
So I was wondering if it could be possible in case 2, also for optimization purpose, to replace the call of the copy constructor by the move constructor, knowing that variable a is never used outside of the construction of b.
Upvotes: 1
Views: 73
Reputation: 13040
To my knowledge there is at least one case (return value optimization) where the compiler can alter the observable behavior of the program by avoiding the call to a copy constructor which has side effect.
These cases are explicitly specified by the standard, and unfortunately, cases like your case 2 are not included, so the compiler is not permitted to perform such an optimization that alters the observable behavior.
Related part in the standard [class.copy.elision]/3:
In the following copy-initialization contexts, a move operation might be used instead of a copy operation:
If the expression in a return statement ([stmt.return]) is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression, or
if the operand of a throw-expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) whose scope does not extend beyond the end of the innermost enclosing try-block (if there is one),
Upvotes: 1