template boy
template boy

Reputation: 10480

Copy-elision doesn't happen when using move

Why does this example print:

#include <iostream>

struct X
{
    X() = default;
    X(X const&) { std::cout << "copy-constructor\n"; }
    X(X&&) { std::cout << "move-constructor\n"; }

    X& operator=(X)
    {
        return *this;
    }
};

int main() 
{
    X x, y;
    std::cout << "assign from prvalue calls the ";
    x = X{};
    std::cout << "\nassign from xvalue calls the ";
    x = std::move(y);
}

assign from prvalue calls the
assign from xvalue calls the move-constructor

Both X{} and std::move(y) are rvalues so why does only assigning to X{} cause copy-elision?

Upvotes: 2

Views: 87

Answers (1)

Mike Seymour
Mike Seymour

Reputation: 254501

Copy elision works in the first case because you're initialising the assignment operator's parameter from a temporary; the temporary can be omitted, constructing the parameter directly instead. In the words of the standard, one of the criteria for elision is:

when a temporary class object that has not been bound to a reference would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

In the second case, you're not initialising it from a temporary, but from an existing object. It has already been constructed, in a different location to the target, so the optimisation described above can't be done.

Upvotes: 11

Related Questions