C ++编译器会优化返回值代码吗?

时间:2013-09-03 13:58:24

标签: c++ rvo

让我们假设我使用Visual Studio或带有-O2的现代GCC。编译器是否会在S中创建func(),然后将其复制到my_result,或者使用构造函数my_result创建(5, 6, 5 + 6)而不创建临时S

注意: 功能func()定义及其用法位于单独的.obj文件中!

struct S
{
    S(int _x, int _y, int _z) : x(_x), y(_y), z(_z) { }
    int x, y, z;
};

S func(int a, int b)
{
    return S(a, b, a + b);
}


/// USAGE ///

S my_result = func( 5, 6 );

5 个答案:

答案 0 :(得分:7)

现代编译器通常会优化这种操作。见return value optimization

答案 1 :(得分:2)

这是一个优化,根据定义,它几乎意味着它对编译器是可选的,并且由每个特定的编译器决定做什么。你怎么能确定?检查生成代码的反汇编!

那说大多数编译器应该进行这种优化(返回值优化[RVO]),因为在这种情况下相对容易做到(没有多次返回,它是一个未命名的临时值,所以你没有别名等)。

答案 2 :(得分:1)

在我看来,提供的测试用例非常简单,可以RVO申请。

答案 3 :(得分:0)

我怀疑临时是否被优化了。您可以通过在构造函数和复制构造函数中放置print语句来测试它,并查看在不同编译器设置下打印的内容。

答案 4 :(得分:0)

您可以自己测试一下,因为所讨论的优化具有可观察到的差异!

C ++中的大多数形式的优化遵循as-if规则,这使得它们难以检测。但是,在少数情况下,允许删除(跳过)复制和移动构造函数,即使差异导致可观察到的行为更改。

在这种情况下,请将以下内容添加到S:

struct S {
  // ...
  S( S const& o ):x(o.x), y(o.y), z(o.z) {
    std::cout << "copy ctor!\n";
  }
  S& operator=( S const& o ) {
    x=o.x;
    y=o.y;
    z=o.z;
    std::cout << "copy assign!\n";
    return *this;
  }
  S( S && o ):x(std::move(o.x)), y(std::move(o.y)), z(std::move(o.z)) {
    std::cout << "move ctor!\n";
  }
  S& operator=( S const& o ) {
    std::tie( x,y,z ) = std::tie( std::move(o.x),std::move(o.y),std::move(o.z) );
    std::cout << "move assign!\n";
    return *this;
  }
}

并运行您的代码。通过零优化,您将获得副本和/或移动。

通过任何非平凡的优化级别,打印将消失,因为RVO(以及相关的情况下,NRVO)将运行,从而消除副本。 (如果你的编译器不是C ++ 11,删除上面的移动构造函数 - 仍然允许在C ++ 03中进行优化)

在C ++ 11中,您可以通过return {stuff}语法显式构造返回值,而不是依赖于NRVO / RVO。

请注意,RVO(返回值优化)和NRVO(命名返回值优化)相对脆弱,如果您依赖它们,您必须了解它们的工作原理,使它们断裂的原因以及您的特定编译器的任何怪癖在其实施中(如果有的话)。