返回本地对象右值引用,正确或错误

Return a local object rvalue reference,right or wrong?

本文关键字:错误 引用 对象 返回      更新时间:2023-10-16

我看到一旦返回一个本地对象,编译器就会进行返回值优化。RVO,NRVO)。

标准祝福RVO的部分继续说,如果 满足 RVO 的条件,但编译器选择不执行 复制 elision,必须将返回的对象视为右值。

所以我们只是写这样的代码:

Widget makeWidget() 
{
 Widget w;
 …
 return w;//never use std::move(w);
}

我从未见过有人写这样的代码:

Widget&& makeWidget()
{
 Widget w;
 …
 return std::move(w); 
}

我知道返回本地对象的左值引用总是错误的。那么,返回本地对象的右值引用也是错误的吗?

返回对局部自动变量的引用总是错误的。当函数返回时,变量将被销毁,因此对引用的任何使用都会给出未定义的行为。

无论是右值还是左值引用都没有区别。

当函数返回时,本地对象已被释放。

如果编写这样的代码:

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

所以答案是错误的。

请注意:

右值引用可用于延长可修改临时的生存期(请注意,对 const 的右值引用也可以延长生存期,但它们不可修改)

每当引用绑定到临时对象或基子对象时 临时的,临时的寿命延长以匹配 引用的生存期,但以下情况除外:

  • 在 return 语句中,临时绑定到函数的返回值不会扩展:它在 返回表达式。此类函数始终返回悬空引用。

  • 函数调用中引用参数的临时绑定一直存在,直到包含该参数的完整表达式结束 函数调用:如果函数返回引用,则引用的寿命超过生存期 完整的表达,它变成了一个悬而未决的参考。

  • 与 new-表达式中使用的初始值设定项中的引用的临时绑定一直存在,直到包含以下内容的完整表达式结束 那个新表达式,不如初始化的对象那么长。如果初始化的对象比完整表达式的寿命长,则其引用成员 成为悬而未决的参考。

Widget&& makeWidget(){
  return Widget(123);//error
}

是的,这是错误的。 不会发生引用生存期延长,因此引用引用已销毁的值,并且使用它(几乎)1 都是未定义的行为。 不应返回悬空引用或指针。


1decltype不是真正的使用,但它也不是UB。 所以就是这样。 存储对它的引用也不是 UB。 也不是真的用。

不幸的是,Widget w;在堆栈上,当您将引用传递给另一个函数时,w将被销毁...按值传递对象将避免对象被销毁。