Ваш пример очень хорош, но ваш компилятор — нет.
Временное значение часто представляет собой буквальное значение, возвращаемое функцией значение, а также объект, передаваемый функции с использованием синтаксиса имя_класса (аргументы_конструктора). Например, до того, как лямбда-выражения были введены в C++, для сортировки вещей нужно было определить некоторую структуру X
с перегруженным operator()
, а затем сделать такой вызов:
std::sort(v.begin(), v.end(), X());
В этом случае вы ожидаете, что время жизни временного объекта, созданного с помощью X()
, закончится точкой с запятой, которой заканчивается инструкция.
Если вы вызываете функцию, которая ожидает ссылку на константу, скажем, void f(const int & n)
, с временным значением, например. f(2)
, компилятор создает временный int
, инициализирует его 2
и передает ссылку на этот временный объект в функцию. Вы ожидаете, что этот временный объект завершит свою жизнь точкой с запятой в f(2);
.
Теперь подумайте об этом:
int && ref = 2;
std::cout << ref;
Этот код вполне действителен. Обратите внимание, однако, что здесь компилятор также создает временный объект типа int
и инициализирует его с помощью 2
. Это временное, к которому привязывается ref
. Однако если бы время жизни временного объекта было ограничено инструкцией, в которой оно создано, и заканчивалось точкой с запятой, отмечающей конец инструкции, следующая инструкция была бы катастрофой, поскольку cout
использовала бы висячую ссылку. Таким образом, ссылки на временные объекты, подобные приведенным выше, были бы довольно непрактичными. Именно для этого и нужно продление срока службы временки. Я подозреваю, что компилятор, увидев что-то вроде int && ref = 2
, может преобразовать его во что-то вроде этого
int tmp = 2;
int && ref = std::move(tmp);
std::cout << ref; // equivalent to std::cout << tmp;
Без расширения срока службы это могло бы выглядеть примерно так:
{
int tmp = 2;
int && ref = std::move(tmp);
}
std::cout << ref; // what is ref?
Делать такой трюк в операторе return было бы бессмысленно. Не существует разумного и безопасного способа продлить время жизни любого объекта, локального для функции.
КСТАТИ. Большинство современных компиляторов выдают предупреждение и сокращают вашу функцию
int&& func()
{
return 42;
}
to
int&& func()
{
return nullptr;
}
с немедленным segfault при любой попытке разыменовать возвращаемое значение.
person
zkoza
schedule
01.03.2021