为什么这里没有使用NRVO优化?

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(命名返回值优化)。但为什么会这样呢?


5
你使用了哪个级别的优化?另外请注意,如果只有一个返回值,那么应用NRVO会更加简单,对于本例来说,这是微不足道的,可以将 if 替换为:if (!j) a.i = j;,这样它就有更高的被应用的可能性。 - David Rodríguez - dribeas
1
请查看这里,http://msdn.microsoft.com/en-us/library/ms364057%28v=vs.80%29.aspx,其中有NRVO的限制。您确定已启用优化吗? - kassak
@DavidRodríguez-dribeas 我已经尝试了所有的优化选项,结果都是一样的。 - Belloc
1
@user1042389:你的例子非常类似于kassak链接中的“示例5”,在那里优化失败,因为析构函数使得控制流对编译器来说太复杂了。同样在那个链接中,它表示:“这实际上是Visual C++ 2005将来需要改善的事情” - 也许他们在2010年之前没有时间进行这一改进。 - Mike Seymour
@MikeSeymour 但是正是析构函数阻止了优化。你有什么想法为什么会这样? - Belloc
@user1042389:除了那篇文章所说的,我也不知道更多了。它会对编译器的优化逻辑造成某种问题,因此编译器放弃了尝试进行优化。其他编译器没有这种限制。 - Mike Seymour
2个回答

6
如果您只是好奇VC10的算法如何决定是否执行NRVO,那么唯一能够可靠回答这个问题的人是那些了解VC10内部工作方式的人 - 即编写它的人。根据C++11标准,如果仅仅是出于好奇,编译器可以在这种情况下执行NRVO,而不执行NRVO仅仅是编译器的决定,没有任何有效性约束。然而,如果您希望强制编译器执行NRVO,则答案是“您不能”。完全由编译器自行决定是否应用NRVO。您不能指望它被执行,也不能指望它不被执行。据我所知,这是所谓的“as-if”规则的唯一例外。这意味着,随着优化级别的提高,执行NRVO的机会也会增加。

我只是好奇为什么这里没有应用。 - Belloc
@user1042389:好的,在这种情况下很难得到一个答案。我可以告诉你的是,C++标准确实允许NRVO(命名返回值优化),所以答案不是“因为不允许”。 - Andy Prowl

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

我在VS2010中使用优化后的发布版本,获得了您的第二个输出。 - Belloc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接