【问题标题】:C++ Return Value OptimizationC++ 返回值优化
【发布时间】:2013-09-09 20:24:58
【问题描述】:

我是 C++ 新手,我在 wiki 和这个网站上阅读了一些关于返回值优化的内容,但是我仍然很好奇以下行为是如何发生的:

using namespace std;
class A
{
    public:
        A()           {cout << "A Ctor" << endl;}
        A(const A &a) {cout << "A copy Ctor" << endl;}
};

A Foo()
{
    A a;
    return a;
}

int _tmain(int argc, _TCHAR* argv[])
{
    cout << "Foo()" << endl;
    Foo();
    cout << "Foo() and new object" << endl;
    A b(Foo());
    return 0;
}

输出是:

Foo()
A Ctor
A copy Ctor
Foo() and new object
A Ctor
A copy Ctor

我的问题是,为什么Foo();A b(Foo()); 都只触发了一次复制构造函数调用?这是否意味着从Foo() 返回的复制值可用于在该位置构造对象b,从而不需要再次调用b 的构造函数?这是基于 Visual Studio 2010。

【问题讨论】:

  • A b(Foo()); 不应该调用任何东西...这是一个函数原型。
  • @0x499602D2: sure about that?
  • @QnA 我敢打赌,您在发布版本中得到的结果与在调试版本中不同。
  • 感谢您的回答,很快! @MooingDuck 你是对的,发布版本摆脱了两个复制 ctor 调用。但我仍然很好奇调试构建中的逻辑是什么,两种情况都只调用一个复制 ctor。
  • 我的猜测。 NRVO 仅在 -O2 优化级别上启动 VC++,而 RVO 始终有效。 A b(Foo()); 是 RVO,编译器使用 b 作为临时。 (关于 RVO 总是 工作是我的猜测。)

标签: c++ c++11 rvo nrvo


【解决方案1】:

返回值优化 (RVO) 指出编译器可以删除一个或两个副本,但这不是必需的。这意味着:

A a (Foo());

可以随意做 0、1 或 2 个拷贝构造函数:

2 - 在函数 Foo() 中,A a 创建一个 A。当它试图返回时,它会将A 复制到返回值中;生成的初始化A a(Foo());Foo() 的结果复制到新的A

1 - 其中一个副本不会发生(可能是复制到 Foo 的返回值中。

0 - 这些副本都不会发生。在Foo 内部创建的A a 直接变成在这一行创建的AA a(Foo());

Msdn 有很多关于visual c++ compiler handles RVO 的详细信息。它有一些简洁的代码示例来解释它是如何有效地工作的。

【讨论】:

  • RVO 和 NRVO 不是完全一样的东西。
  • 不完全相同,不,但非常相似。这应该有助于@QnA 理解。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-02
相关资源
最近更新 更多