我对返回值优化感到困惑,以下是示例。
#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);
陈述之前。
答案 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
。