c++copy-elisionnrvo

C++ copy elision when returning a function argument


I'm puzzled as to how this code compiles: (https://godbolt.org/z/hjY4ca4rr)

class A
{
public:
    A() = default;
    A(A &&other) = default;

    int x = 0;
};

A f(A a)
{
    a.x = 1;
    return a;
}

int main()
{
    f(A());
    return 0;
}

In principle, returning a from f() means copying it to the call-site location, but an A is not copy-able. NRVO copy elision may kick in but:

Anyone cares to clarify?


Solution

  • As Jarod pointed out, it's not doing a copy, but a move, since the compiler knows the variable won't be used afterwards So it's using the A(A &&other) constructor To verify it, you can just print out something in the constructor

    Also, if you want to disable copy, I recommend you to explicitly write it (and follow the rule of five).

    That leads us to this code:

    #include <iostream>
    
    class A
    {
    public:
        A() = default;
        A(A &&other)
        {
            std::cout << "A(A&&)" << std::endl;
        }
        A(const A&other) = delete;
        A& operator=(const A &other) = delete;
    
        A& operator=(A &&other)
        {
            std::cout << "A& operator=(A &&)" << std::endl;
            return *this;
        }
    
        ~A() = default;
    
        int x = 0;
    };
    
    A f(A a)
    {
        a.x = 1;
        return a;
    }
    
    int main()
    {
        f(A());
        return 0;
    }
    

    Output:

    A(A&&)
    

    So it is definitely calling the move constructor.