何时需要返回值优化/应用?

时间:2015-08-27 15:44:52

标签: c++

我对返回值优化感到困惑,以下是示例。

#include <iostream>
using namespace std;
class A{
    int x;
    public:
        A(int val=0):x(val){
            cout << "A" << x << endl;
        }
        A(const A& a){
            x=a.x;
            cout << "B " << x << endl;
        }
        void SetX(int x){
            this -> x=x;
        }
        ~A(){
            cout << "D " << x << endl;
        }
};
A f(A a){
    cout << "C " << endl;
    a.SetX(100);
    return a;
}
int main(){
    A a(1);
    A b=f(a); // Why Copy constructor instead of RVO?
    b.SetX(-100);
    return 0;
}

输出

A 1 // ok
B 1 // ok
C // ok
B 100 // why it's here? Why copy constructor instead of RVO?
D 100 // why after the above line? it should be before the above line.
D -100 // ok 
D 1 // ok

我对B 100和D 100输出感到困惑。

1)为什么编译器给出B 100输出它应该是RVO(不应该调用复制构造函数)。

2)第二个是如果调用了复制构造函数,那么D 100应该在B 100之前,因为fun()函数对象超出了范围。在A b=f(a);陈述之前。

3 个答案:

答案 0 :(得分:2)

首先,永远不需要RVO。这是允许的,这使它有很大的不同。

EDIT。

关于构造函数的顺序,我的初始答案是不正确的。我错过了输出中的那一行,事实上,它只是意味着复制省略并没有完全成功。 3个专业副本(从f()到临时位置,通过返回a;从临时位置到b = f(a)的右侧;从右侧到b)一个没有被删除,完全复制。我不知道是哪一个。

答案 1 :(得分:1)

  

1)为什么编译器给出B 100输出它应该是RVO(不应该调用复制构造函数)。

是的,应该调用它,因为您正在获取a的副本作为参数。

  

D 100

发生是因为在return语句之后,a超出了范围。

答案 2 :(得分:1)

RVO或更具体地说,命名返回值优化(NRVO),是一种复制省略,根据标准允许在以下情况下[12.8 / 31]:

  

在具有类返回类型的函数的return语句中,当表达式是a的名称时   非易失性自动对象(除函数或catch-clause 参数)具有与函数返回类型相同的cv-nonqualified类型,复制/移动操作可以是通过构造省略   自动对象直接进入函数的返回值[强调我的]

因此,在这种情况下不允许使用RVO,因为a是函数参数。

在函数结束之前,但在为a获取返回值的副本之后,它必须销毁临时变量a