8

当我在 VS2010 中运行此代码时,未应用 NRVO。

#include <stdio.h>

class A
{
    public:

    A() { printf( "I am in constructor\n" ); }
    A(const A& a) { printf( "I am in copy constructor\n" ); }
    ~A() { printf( "I am in destructor\n" ); }
    int i;       
};

A f(int j)
{
    A a;
    if ( j )  return a;
    a.i = j;
    return a; 
}

int main()
{
    A a;
    a = f(5);
}

编辑:这与析构函数有关。当我注释掉它的行时,使用的是 NRVO。但这是为什么呢?

4

2 回答 2

6

为什么这里没有应用 NRVO?

如果这纯粹是您的好奇心,并且您想知道 VC10 如何通过算法决定是否执行 NRVO,那么唯一可以可靠地回答这个问题的人是那些知道 VC10 内部如何工作的人——那些编写它的人。

据我所知,根据 C++11 标准,允许编译器在这种情况下执行 NRVO,不这样做只是编译器的决定——不是由于任何有效性约束。根据第 12.8/31 段:

[...]这种复制/移动操作的省略,称为复制省略,在以下情况下是允许的(可以结合起来消除多个副本):

在具有类返回类型的函数的返回语句中,当表达式是具有与函数返回类型相同的 cv 非限定类型的非易失性自动对象(函数或 catch 子句参数除外)的名称时,可以通过将自动对象直接构造到函数的返回值中来省略复制/移动操作

[...]

但是,如果您希望能够强制编译器执行 NRVO,那么答案是“您不能”。

是否应用 NRVO 完全由编译器自行决定。你不能指望它,你不能指望它被执行。据我所知,这是所谓“好像”规则的唯一例外。

这就是说,随着优化级别的提高,执行 NRVO 的机会也会增加。

于 2013-04-16T13:37:23.560 回答
1

我不知道您在您的环境中看到了什么,但这在 GCC 中按预期工作(例如,请参见此处):

普通的:

I am in constructor
I am in constructor
I am in destructor
I am in destructor

-fno-elide-constructors

I am in constructor
I am in constructor
I am in copy constructor
I am in destructor
I am in destructor
I am in destructor
于 2013-04-16T13:38:11.330 回答