为什么这里不使用NRVO ?

Why NRVO is not applied here?

本文关键字:NRVO 这里 为什么      更新时间:2023-10-16

在VS2010中运行此代码时不应用NRVO。

#include <stdio.h>
class A
{
    public:
    A() { printf( "I am in constructorn" ); }
    A(const A& a) { printf( "I am in copy constructorn" ); }
    ~A() { printf( "I am in destructorn" ); }
    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。但这是为什么呢?

为什么这里不使用NRVO ?

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

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

[…复制/移动操作的省略,称为复制省略,在以下情况下是允许的(其中可以组合以消除多个副本):

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

[…]

然而,如果你期望你应该能够强迫编译器执行NRVO,那么答案是"你不能"。

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

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

我不知道你在你的环境中看到了什么,但这在GCC中是预期的(例如见这里):

正常:

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

With -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