我一直在阅读Myers的书,并通过引用/指针和值返回来查看项目。 关键是,如果我们的函数是这样的:
ClassA& AddSomething(ClassA classA)
{
ClassA tempClassA;
//... do something on tempClassA
return tempClassA;
}
这不起作用,因为我们正在返回对堆栈上创建的对象的引用,现在该函数已经完成。
他给出了两个解决方案:
作为对象返回:
ClassA AddSomething(ClassA classA)
{
ClassA tempClassA;
//... do something on tempClassA
return tempClassA;
}
现在,如果我要这样做:
ClassA obj1;
ClassA obj2 = AddSomething(obj1);
现在我的困惑是,在执行这一行时:
基本上,传递给复制构造函数的是对tempClassA的引用(在函数内部的堆栈中创建)或对tempClassA副本的引用。
另外,我的另一个问题是,我已经读过,如果我得到一个函数局部变量的引用,那么本地变量将不会被删除。 例如,
ClassA & classRef = AddSomething(obj1);
在这种情况下,如果AddSomething()返回引用,则classRef不会指向已删除的引用,因为将保留本地变量。我理解正确吗?
答案 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引用它时,它将是对不存在的对象的悬空引用。