Return 堆分配变量的值优化和初始化

Return Value Optimization And Initializaton of Heap Allocated Variables

从临时 RVO 初始化堆栈分配变量时发生,但在初始化堆分配变量时不会发生。

#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
} 

输出: 移动 A!

在我看来,编译器正在堆栈中创建 A,获取指向堆分配内存的指针,然后移动 A,但为什么它不先获取指针然后然后传给foo,这样A就可以直接在堆分配的chunk中构造了?

编辑: 使用 g++(i686-posix-dwarf-rev0,由 MinGW-W64 项目构建)5.3.0 编译,使用 -O3 -std=c++17

编辑 2: 更新到 MinGW 7.4.0,现在它优化了复制和移动。

它可以,需要额外的努力,the rules of C++17 actually require your compiler to go to this effort

所以进入 C++17 模式并尽情享受吧!

(live demo)

如果您出于某种原因不想使用 C++17,只要您使用支持它的编译器,那么它很可能会在早期的标准模式中应用此优化(因为他们已经不得不编写执行此操作的代码)。例如,即使在 -O0,Coliru 的 GCC 在 C++14 模式下也是如此。换句话说,也许你只需要升级你的编译器。

如果您的编译器在 C++17 模式下执行此操作,则它 non-compliant 符合标准。

这可能是一个错误,例如 this old GCC bug; MinGW-w64 v5.0.3 should approximate to GCC 7.2.0,我知道这个错误需要修复,但由于 MinGW 不是 GCC 代码库的直接克隆,因此它在这方面可能略有落后。您可以尝试升级到 MinGW-x64 v6。

我还发现 Visual Studio 2017 的复制省略不可靠。