4

我一直在阅读 Myers 的书,并在通过引用/指针与按值返回时遇到了该项目。关键是,如果我们的函数例如是这样的:

ClassA& AddSomething(ClassA classA)
{
  ClassA tempClassA;
  //... do something on tempClassA
  return tempClassA;
}

这不起作用,因为我们正在返回对在堆栈上创建的对象的引用,并且现在函数完成后它已经死了。

他给出了两个解决方案:

  1. 在函数内部使用本地静态 ClassA。这有其问题,但至少我们可以确定该对象存在。
  2. 作为对象返回:

    ClassA AddSomething(ClassA classA)
    {
      ClassA tempClassA;
      //... do something on tempClassA
      return tempClassA;
    }
    

现在,如果我要做:

ClassA obj1;
ClassA obj2 = AddSomething(obj1);

我现在的困惑是,在执行这一行时:

  1. 制作 tempClassA 的“副本”并将其传递给 ClassA 的复制构造函数(以初始化 obj2)?或者
  2. tempClassA 将自身传递给 ClassA 的复制构造函数,因为复制构造函数需要一个引用。

所以基本上,传递给复制构造函数的是对 tempClassA 的引用(在函数内部的堆栈中创建)或对 tempClassA 副本的引用。

另外,我的另一个问题是,我已经读过,如果我得到一个函数局部变量的引用,在这种情况下,局部变量将不会被删除。例如,

ClassA & classRef = AddSomething(obj1);

在这种情况下,如果 AddSomething() 返回一个引用,则 classRef 不会指向已删除的引用,因为将保留局部变量。我是否正确理解了这一点?

4

3 回答 3

5

在最坏的情况下,你是对的:一个副本tempClassA被传递给复制构造函数。但是允许编译器消除该副本并在适当的位置构造结果形式tempClassA。这被称为“返回值优化”或 RVO。我不知道不这样做的编译器。

于 2012-08-30T14:10:12.177 回答
2

当一个对象按值返回时,会发生两份副本:一份从局部变量到返回值,另一份从返回值到目标对象。但是,允许实现省略这些副本中的一个或两个;这在第一种情况下称为返回值优化(RVO),在第二种情况下称为复制省略。

Object some_function() {
    return Object();    // copy Object() into return value; candidate for RVO
}
Object another_function() {
    Object obj;
    return obj;         // copy obj into return value; candidate for NRVO
}
Object result = some_function();   // copy return value into result; candidate for copy elision

上面的第二个函数是 RVO 细化类型的候选函数,称为命名返回值优化;RVO 的最简单形式仅适用于在原地构造返回值的返回语句。

关于您的第二个问题,生命周期延长仅适用于对按值返回的对象的const引用;您在第二个问题中的代码不会延长任何对象的生命周期。有关更多详细信息,请参阅返回临时对象并绑定到 const 参考

于 2012-08-30T14:12:03.620 回答
0

您永远不能通过引用返回函数局部变量。即使您使用 const 引用来捕获返回值,它也不起作用,如下所示:

const ClassA& classRef = AddSomething(obj1);

因为如果 AddSomething 通过引用返回一个本地对象,那么当 classRef 引用它时,它将是一个对不存在对象的悬空引用。

于 2012-08-30T14:38:26.577 回答