c++rvo

Return Value Optimization And Initializaton of Heap Allocated Variables


When initializing a stack allocated variable from a temporary RVO occurs, but it doesn't when initializing a heap allocated variable.

#include <iostream>
using namespace std;

class A
{
public:
    A() = default;

    A(const A &other)
    {
        cout << "Copy A!" << endl;
    }

    A(A &&other)
    {
        cout << "Move A!" << endl;
    }
};

A foo()
{
    return A();
}

int main()
{
    A a1 = foo(); //Constructs A only!
    A *a2 = new A(foo()); //Constructs A and moves it
} 

Output: Move A!

It seems to me that the compiler is creating A in the stack, getting the pointer to heap allocated memory and then moving A, but why doesn't it just gets the pointer first and then passes it to foo, so A can be constructed directly in the heap allocated chunk?

EDIT: Compiled with g++ (i686-posix-dwarf-rev0, Built by MinGW-W64 project) 5.3.0, using -O3 -std=c++17

EDIT 2: Updated to MinGW 7.4.0 and now it optimizes out both the copy and the move.


Solution

  • It can, with a little extra effort, and the rules of C++17 actually require your compiler to go to this effort.

    So put on C++17 mode and enjoy!

    (live demo)

    If you don't want to use C++17 for whatever reason, as long as you use a compiler that supports it then it will likely apply this optimisation in earlier standard modes anyway (since they already had to write the code to do it). For example, Coliru's GCC does so in C++14 mode even at -O0. In other words, perhaps you simply need to upgrade your compiler.

    If your compiler doesn't do this in C++17 mode, it is non-compliant to the standard.

    That could be a bug, like this old GCC bug; MinGW-w64 v5.0.3 should approximate to GCC 7.2.0, in which I understand the bug to be fixed, but as MinGW is not a direct clone of the GCC codebase it could be lagging behind slightly in this regard. You could try upgrading to MinGW-x64 v6.

    I've also found Visual Studio 2017 to have unreliable copy elision.