I'm returning non-named object from a function. Why RVO still kicks in?

315 Views Asked by At

Regarding this: Why does std::move prevent RVO? someone wrote that: "Hence in a return statement copy elision can only occur, if the expression is the name of a local variable"

However I made a little test with GCC:

class X
{
public:
    X()
    {
        cout << "def" << endl;
    }
    X(const X& x)
    {
        cout << "copy" << endl;
    }
    X(X&& x)
    {
        cout << "move" << endl;
    }
};

X produceX()
{
    return X();
}

int main()
{
    X x{produceX()};
    return 0;
}

The produceX function does not return a named value. It returns an unnamed temporary object. However the RVO still kicks and there is no copy nor move construction. The x object from main is constructed in-place. If I write produceX like this:

X produceX()
{
    X localNamedObject;
    return localNamedObject;
}

it behaves the same way (which is expected). But why RVO is allowed in the former case?

2

There are 2 best solutions below

3
On BEST ANSWER

That statement is an over-simplification, although the answer you took it from does in fact answer this question, and provides the relevant text from the standard.

Copy elision is allowed when returning a temporary (as a general case of using a temporary to initialise an object of the same type), as well as when returning a local variable.

It's also allowed when throwing and catching exceptions by value, but that's beyond the scope of this question.

0
On

RVO stands for "return value optimization" and refers to the technique of constructing the return expression result directly within the return value space. It is applied when the return expression is an rvalue.

NRVO stands for "named return value optimization" and refers to the technique of constructing the named object that will eventually be returned directly within the return value space. It is applied when the return expression is an lvalue.