我看到一旦返回一个本地对象,编译器将采用返回值优化。(RVO,NRVO)。
标准祝福RVO的部分继续说,如果 满足RVO的条件,但编译器选择不执行 复制省略,返回的对象必须被视为右值。
所以我们只写这样的代码:
Widget makeWidget()
{
Widget w;
…
return w;//never use std::move(w);
}
我从未见过有人写过这样的代码:
Widget&& makeWidget()
{
Widget w;
…
return std::move(w);
}
我知道返回本地对象的左值引用总是错误的。 那么,返回本地对象的右值引用也是错误的?
答案 0 :(得分:23)
返回对本地自动变量的引用总是错误的。当函数返回时,变量将被销毁,因此对引用的任何使用都将给出未定义的行为。
它是右值还是左值参考没有区别。
答案 1 :(得分:4)
当函数返回时,本地对象已被释放。
如果写这样的代码:
Widget&& makeWidget()
{
Widget w;
…
return std::move(w);
}
因此,请考虑以下三段代码:
<强>首先强>
Widget&& w= makeWidget();//w is a dangling reference,variable will be destroyed when the function returns
<强>第二强>
void foo(Widget&& w){...}//w is a dangling reference too
foo(makeWidget());
<强>第三强>
void foo(Widget w){...}//OK,will copy it
foo(makeWidget());
所以回答错了。
Rvalue引用可用于延长可修改临时值的生命周期(注意,对const的左值引用也可以延长生命周期,但它们不可修改)
每当引用绑定到临时或基础子对象时 一个临时的,临时的生命周期延长到匹配 参考的生命周期,包含以下例外:
一个临时绑定到return语句中函数的返回值不会被扩展:它会在结束时立即销毁 返回表达式。此类函数始终返回悬空参考。
存在于函数调用中的引用参数的临时绑定,直到包含该参数的完整表达式结束 函数调用:如果函数返回一个引用,则该函数寿命更长 完整的表达,它成为一个悬垂的参考。
临时绑定到new-expression中使用的初始值设定项中的引用,直到包含完整表达式的结尾为止 那个new-expression,不像初始化对象那么长。如果初始化对象超出完整表达式,则其引用成员 成为一个悬垂的参考。
Widget&& makeWidget(){
return Widget(123);//error
}
答案 2 :(得分:3)
是的,这是错的。没有引用生命周期扩展,因此引用引用了一个被破坏的值,并且它(几乎) 1 的任何使用都是未定义的行为。你不应该返回悬空引用或指针。
1 :decltype
并没有真正使用,但它也不是UB。所以就是这样。存储对它的引用也不是UB。也没用。
答案 3 :(得分:2)
不幸的是Widget w;
在堆栈上,当您将引用传递给另一个函数时,w
将被销毁...按值传递对象将保存对象不被破坏。 / p>