каковы правила, когда возвращаемый тип является ссылкой - PullRequest
1 голос
/ 03 апреля 2020
#include <iostream>
int func0(){
  int a = 0;
  return a;
}
int&& func1(){
   int a = 0;
   return a;
}
int main(){
  int&& result0 = func0();
  int&& result1 = func1();
}

return statement правила:

  1. Функция возвращается к своему вызывающему оператору с помощью оператора return.
  2. [...] оператор return инициализирует объект результата glvalue или результат результата prvalue (явного или неявного) вызова функции путем инициализации копирования из операнда.

Правило инициализации объекта вызова функции - только # 2.

Мы знаем, что выражение func0() является prvalue. Ссылка result0 должна связать объект, поэтому temporary materialization conversion должна преобразовать значение prvalue в значение xvalue. Таким образом, временный объект как объект результата prvalue инициализируется из операнда return, затем ссылка reusult0 привязывается к временный объект.

Но мы знаем, что result1 является ссылкой, а тип возвращаемого значения func1 также является ссылкой. Для этого случая [stmt.return] явно не охватывает этот случай, потому что result1 является ссылкой, а не object (ни объект glvalue reuslt, ни объект результата prvalue), так что правила о этот случай? Если я что-то упустил, поправьте меня.

Ответы [ 3 ]

3 голосов
/ 03 апреля 2020

Ваш анализ result0 правильный.

Но в случае result1 временная материализация отсутствует. «Результат glvalue» - это ссылка, инициализированная инициализацией копирования из операнда a, а инициализация копирования ссылки того же типа означает, что ссылка связывается напрямую (dcl.init.ref / 5, через dcl.init /17.2). Затем result1 связывается с результатом glvalue.

Это создает висячую ссылку; оператор return явно исключен из правил продления времени жизни (class.teven / 6.2).

В случае int result2 = func1();, тогда результат glvalue (ссылка) подвергается преобразованию lvalue в rvalue с результатом объект result2, это вызывает неопределенное поведение, так как результат glvalue зависал.

2 голосов
/ 03 апреля 2020

Мы знаем, что выражение func0 является prvalue

Неправильно. func0 (выражение имени функции) является lvalue. Вы думаете о func0() (выражение вызова функции), которое действительно является prvalue. Остальная часть абзаца верна.

Я действительно не следую вашему второму абзацу, поэтому позвольте мне сформулировать это так:

func1() - это xlvalue, а ссылка result будет привязана к это значение x.

Очень важно: поскольку вы возвращаете ссылку на автоматическую переменную хранения c, у вас остается висячая ссылка.

1 голос
/ 03 апреля 2020

Для этого случая [stmt.return] явно не охватывает этот случай, поскольку result1 является ссылкой, а не объектом (ни объектом glvalue reuslt, ни объектом результата prvalue), ...

Нет, это покрывает. Обратите внимание, что правило гласит «результат результата glvalue или объект результата prvalue», который не является «результатом результата glvalue объект или объект результата prvalue». См. [basi c .lvalue] / 5 :

Результатом glvalue является объект, обозначаемый выражением. Результат значения prvalue - это значение, которое выражение хранит в своем контексте; prvalue типа cv void не имеет результата. Иногда говорят, что prvalue, результатом которого является значение V, имеет или присваивает ему значение V. Объект результата для prvalue является объектом, инициализированным prvalue; ...

Таким образом, эталонная сущность результата func1() инициализируется с a.

...