Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any special reason why the move constructor is not elided in the snippet shown below?

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

like image 980
Belloc Avatar asked Sep 27 '15 19:09

Belloc


1 Answers

According to 12.8 [class.copy] paragraph 31, second bullet the copy of a local variable being thrown can be elided:

in a throw-expression, when the operand 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), the copy/move operation from the operand to the exception object (15.1) can be omitted by constructing the automatic object directly into the exception object

It seems none of the compilers makes use of this optimization. One reason could be that it is simply not worth doing so far as the effort is better spent on other optimizations. I don't think there is anything in the standard prohibiting this optimization.

like image 63
Dietmar Kühl Avatar answered Nov 18 '22 09:11

Dietmar Kühl