Вернуть ссылку на локальный объект rvalue, правильно или неправильно?

Я вижу, как когда-то возвращают локальный объект, компилятор будет использовать оптимизацию возвращаемого значения. (RVO, NRVO).

Часть Стандартного благословения RVO продолжает утверждать, что если условия для RVO выполнены, но компиляторы предпочитают не выполнять copy elision, возвращаемый объект должен рассматриваться как rvalue.

Итак, мы просто пишем код следующим образом:

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

Я никогда не вижу, чтобы кто-нибудь написал такой код:

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

Я знаю, что возврат ссылки lvalue локального объекта всегда неверен. Итак, возвращает ссылку rvalue локального объекта также неверно?

Ответ 1

Возвращение ссылки на локальную автоматическую переменную всегда неверно. Переменная будет уничтожена, когда функция вернется, поэтому любое использование ссылки даст поведение undefined.

Не имеет значения, является ли это ссылкой rvalue или lvalue.

Ответ 2

Да, это неправильно. Никакое расширение жизненного цикла ссылки не происходит, поэтому ссылка ссылается на уничтоженное значение, и любое его использование (почти) 1 - это поведение undefined. Вы не должны возвращать висячие ссылки или указатели.


1: decltype на самом деле не используется, но это также не UB. Так и есть. Хранение ссылки на него также не является UB. Также не используется.

Ответ 3

К сожалению, Widget w; находится в стеке, и пока вы передаете ссылку на другую функцию, w будет уничтожен... Передача объекта по значению спасет объект от уничтожения.

Ответ 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 могут использоваться для продления времени жизни изменяемого временного (примечание, ссылки lvalue на const могут также продлить сроки жизни, но они не изменяются)

Всякий раз, когда ссылка привязана к временному или к базовому подобъекту временный срок жизни временного продления соответствует время жизни ссылки со следующими исключениями:

  • временная привязка к возвращаемому значению функции в операторе return не распространяется: она немедленно уничтожается в конце обратное выражение. Такая функция всегда возвращает оборванную ссылку.

  • временная привязка к ссылочному параметру в вызове функции существует до конца полного выражения, содержащего вызов функции: если функция возвращает ссылку, которая переживает полное выражение, оно становится свисающей ссылкой.

  • временная привязка к ссылке в инициализаторе, используемом в новом выражении, существует до конца полного выражения, содержащего это новое выражение, но не до тех пор, пока инициализированный объект. Если инициализированный объект переживает полное выражение, его ссылочный элемент становится болтающей ссылкой.

Widget&& makeWidget(){

  return Widget(123);//error
}