Qubc
@Qubc
Ненавижу полисемию.

Почему нельзя возвращать объект по значению в non-const &?

https://godbolt.org/z/dqTffoGPn

В ассемблерных кодах при вызове фукнции struct s f ( void ), которая возвращает объект по значению, память для объекта на самом деле выделяется внутри кадра стека main() заранее. В функцию скрытно передаётся адрес этого объекта, а внутри функции объект не создаётся. Очень круто.

Но верно ли я понимаю, что запрет на возврат "объекта по значению" в ссылку на non-const - это чисто синтаксическое правило, а не техническое ограничение?

spoiler

const reference или const & термины полностью отражают суть механизма и они используются в англ. книгах.
Верно ли я понимаю, что перевод "ссылка на константу" совсем ошибочен, потому что "константа" это вообще другая история?
Верно ли, что правильно говорить "ссылка на объект с const квалификатором" ?
Верно ли, что не совсем правильно, но короче говорить "ссылка на константный объект" ?
  • Вопрос задан
  • 221 просмотр
Решения вопроса 1
wataru
@wataru Куратор тега C++
Разработчик на С++, экс-олимпиадник.
Первое - это Retrun Value Optimization. Компилятор видит, что результат работы функции используется для инициализации переменной и вместо выделения памяти под временный объект и копирования сразу заполняет результат.

По поводу ссылки. Результат работы функции в вашем случае - prvalue

там же по ссылке написано:
An rvalue may be used to initialize a const lvalue reference, in which case the lifetime of the object identified by the rvalue is extended until the scope of the reference ends.

An rvalue may be used to initialize an rvalue reference, in which case the lifetime of the object identified by the rvalue is extended until the scope of the reference ends.


Т.е. стандартом запрещено инициализировать не const ссылку через prvalue.

Почему это сделано? Потому что эти самые prvalue/rvalue по сути являются временными объектами. У них нельзя взять адрес, у них нет имени, компилятор может засунуть их куда угодно и уничтожить сразу за текущим выражением.

Если бы можно было делать ссылку на эти временные объекты и как-то их менять потом, это бы усложняло анализ и возможность некоторых оптимизаций. Как, например, RVO в вашем вопросе. Пришлось бы создавать временную переменную в main для хранения результата, потому что функция память под результат не выделяет. Поэтому в стандарте C++ этого нет.

Потом, когда в С++11 ввели rvalue ссылки и перелопатили категории значений - разрешили инициализировать rvalue ссылки через prvalue.

Поэтому работают
const int& r1 = f();
int&& r2 = f();
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@Mercury13
Программист на «си с крестами» и не только
const struct s & ref = f();
Этот механизм называется «продление жизни временного объекта».
Можно написать вот так.
struct s && ref = f();

Главная причина преобразования временного объекта только в const T& и T&& — тонкие ошибки при суперпозиции функций.
А именно — временный объект мы ни в коем случае не должны передать в функцию, принимающую s&.
void modify(s& arg) { ++arg[1]; }

...

modify(f());

Мы вызвали функцию f(), её результат передали в modify, и… похѣрили.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы