C ++:按引用返回按值返回

时间:2012-08-30 14:06:30

标签: c++ pass-by-reference

我一直在阅读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;
    }
    
  3. 现在,如果我要这样做:

    ClassA obj1;
    ClassA obj2 = AddSomething(obj1);
    

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

    1. 制作tempClassA的'副本'并将其传递给复制构造函数 ClassA(初始化obj2)? OR
    2. tempClassA将自身传递给ClassA的复制构造函数, 因为复制构造函数需要引用。
    3. 基本上,传递给复制构造函数的是对tempClassA的引用(在函数内部的堆栈中创建)或对tempClassA副本的引用。

      另外,我的另一个问题是,我已经读过,如果我得到一个函数局部变量的引用,那么本地变量将不会被删除。 例如,

      ClassA & classRef = AddSomething(obj1);
      

      在这种情况下,如果AddSomething()返回引用,则classRef不会指向已删除的引用,因为将保留本地变量。我理解正确吗?

3 个答案:

答案 0 :(得分:5)

最糟糕的是,你是对的:tempClassA的副本被传递给复制构造函数。但是允许编译器消除该副本并以tempClassA形式构造结果。这称为“返回值优化”或RVO。我不知道编译器没有这样做。

答案 1 :(得分:2)

当按值返回对象时,会发生两个副本:一个从局部变量返回到返回值,另一个从返回值返回到目标对象。但是,允许实施 elide 这些副本中的一个或两个;这在第一种情况下称为return value optimisation(RVO),在第二种情况下称为copy elision

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 对value返回的对象的引用;第二个问题中的代码不会延长任何对象的生命周期。有关详细信息,请参阅Returning temporary object and binding to const reference

答案 2 :(得分:0)

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

const ClassA& classRef = AddSomething(obj1);

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