4
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()

现在输出将是

构造函数
复制构造函数

所以我的假设是在这里通过返回*this(1) 我们将*this对象值复制到一个新的临时 Cents 对象。这就是调用复制构造函数的原因。

现在,如果我将第 (1) 行替换为

Cents Add(int val){ Cents temp;return temp;}  // --->(2)

唯一的输出是

构造函数

为什么不调用复制构造函数?我对第 (1) 行的假设是错误的吗?

4

2 回答 2

11

这是一种称为复制省略的优化,喜欢缩写词的人有时将其称为“(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 标准,12.8/31。

于 2013-08-15T12:36:40.223 回答
3

发生这种情况是因为大多数编译器执行返回值优化(又名 RVO)以节省复制。

于 2013-08-15T12:33:59.293 回答