首页 > 解决方案 > 堆分配变量的返回值优化和初始化

问题描述

从临时 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在堆分配的块?

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

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

标签: c++rvo

解决方案


它可以,只需付出一点额外的努力,C++17 的规则实际上需要你的编译器去努力

所以换上 C++17 模式,尽情享受吧!

现场演示

如果您出于某种原因不想使用 C++17,只要您使用支持它的编译器,那么它很可能会在早期的标准模式中应用此优化(因为他们已经必须编写代码来做到这一点)。例如,Coliru 的 GCC 即使在-O0. 换句话说,也许您只需要升级您的编译器。

如果您的编译器在 C++17 模式下这样做,则它不符合标准。

这可能是一个错误,就像这个旧的 GCC 错误;MinGW-w64 v5.0.3应该近似于 GCC 7.2.0,我理解要修复的错误,但由于 MinGW 不是 GCC 代码库的直接克隆,它在这方面可能会稍微落后。您可以尝试升级到 MinGW-x64 v6。

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


推荐阅读