Ismael EL ATIFI
Ismael EL ATIFI

Reputation: 2108

Copy constructor called with a variable used only once. Could this be a case for compiler optimization by calling the move constructor instead?

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

Answers (2)

xskxzr
xskxzr

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

P.W
P.W

Reputation: 26800

Although it is possible to get a temporary lvalue without a name (see this question), that is not what is happening here.

In case 2, a is not a temporary but a named lvalue, so no elison happens and copy constructor is called.

Upvotes: 0

Related Questions