gcc, clang and VS2015 don't elide the call to the move constructor in the code below, after throwing object a
. It seems to me the conditions established in bullet point (31.2) of §8.12[class.copy]/31 (N4140) are satisfied.
#include <iostream>
struct A
{
A() { std::cout << "Default ctor " << '\n'; }
A(const A& a) { std::cout << "Copy ctor" << '\n'; }
A(A&& a) { std::cout << "Move ctor" << '\n'; }
~A() { std::cout << "Destructor " << '\n'; }
};
int main()
{
try
{
A a;
throw a;
}
catch(A& a) { std::cout << "Caught" << '\n'; }
}
Note that a
is an lvalue, but according to §12.8/32, overload resolution
to select the constructor for the copy is first performed as if the object were designated by an rvalue. That is, the call to the move constructor is OK. If you erase the definition of the move constructor above, the copy constructor is invoked, but again, it is not elided!
I understand the copy-elision is not mandated by the Standard, but I'm curious to know if there is any special condition that could justify the fact, that the three compilers mentioned above avoid this optimization, in this particular example.
An example output for gcc, from the link above:
g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
Default ctor
Move ctor
Destructor
Caught
Destructor
b
copy-initialized froma
. However, as already discussed, removing the side effect from the default destructor does not elidea
in this case, with g++. It could do that under the as-if rule. – Ankylosaur