【问题标题】:Return Value Optimization And Initializaton of Heap Allocated Variables堆分配变量的返回值优化和初始化
【发布时间】:2019-07-20 20:46:05
【问题描述】:

在从临时 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,但是为什么它不先获取指针然后然后通过it to foo,所以A可以直接在堆分配的chunk中构造?

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

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

【问题讨论】:

  • 如果你在 C++17 模式下编译,你应该在这两种情况下都看不到副本和移动。
  • 用什么输出?编译器?版本?平台?
  • 你确定是MinGW-W64 v5.3.0吗?该版本似乎不存在。
  • @LightnessRacesinOrbit 他们可能意味着 gcc 5.3.0 的 mingw-w64 构建。这是从 2015 年开始的,这将解释不完整的 C++17 支持

标签: c++ rvo


【解决方案1】:

它可以,只需付出一点额外的努力,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 模式下执行此操作,则它不符合标准。

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

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

【讨论】:

  • 是的,看来我的编译器不符合标准,但它是一个非常普遍的编译器,真的很奇怪,我第一次考虑更换编译器。
  • MinGW 确实有其局限性;这不会是第一次。不过,您的版本相当于 GCC 7,它有点旧。值得注意的是,我发现 Visual Studio 的保证省略支持也有些欠缺。
  • (虽然这个版本的 GCC does purport to support guaranteed elision
  • @HenriqueInonhe 我想我找到了错误参考
  • 说实话这个编译器不是我自己安装的,它是Qt自带的,我看看能不能在不破坏任何东西的情况下更新它
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-12
  • 2017-04-10
  • 1970-01-01
  • 2021-07-08
  • 2015-12-23
  • 1970-01-01
  • 2011-01-11
相关资源
最近更新 更多