Class Cents(){
int m_val;
public:
Cents(int x=0){ cout<<"Constructor";}
Cents(const Cents& src){ cout<<"Copy constructor"}
Cents Add(int val){m_val=val; return *this} // --->(1)
}
假设我Cents object obj
并且正在调用obj.Add()
现在输出
构造
复制构造函数
所以我的假设是这里通过在(1)中返回*this
,我们将*this
对象值复制到新的临时Cents对象。这就是调用复制构造函数的原因。
现在如果我用
替换line(1)Cents Add(int val){ Cents temp;return temp;} // --->(2)
唯一的输出是
构造
为什么没有调用复制构造函数?关于第(1)行的假设是错误的吗?
答案 0 :(得分:11)
这是一种称为 copy elision 的优化,有时也被称为“(N)RVO”(用于“(命名)返回值优化”),喜欢首字母缩略词的人。
在某些情况下,当(在概念上)在一个地方创建一个对象,复制或移动到另一个对象然后销毁时,程序可以在最后的位置创建它。即使被省略的构造函数和/或析构函数具有副作用,也允许进行此优化,就像在您的示例中一样。
从函数返回临时变量或局部变量就是这些情况之一。而不是在函数的堆栈框架中创建temp
然后将其复制到调用者的程序,程序可以直接在调用者的框架中创建它。
当您返回*this
时,无法省略副本,因为*this
的有效期超出了该功能。从调用者的角度来看,会有两个对象,因此程序必须实际复制:
Cents original;
Cents copy = original.Add(42);
// "copy" and "original" both exist: the object must have been copied.
有关此优化可以省略哪些操作的完整详细信息,请参阅C ++ 11 Standard,12.8 / 31.
答案 1 :(得分:3)
这是因为大多数编译器执行Return Value Optimization(又称RVO)以节省复制。