Расширенное время жизни объекта, возвращаемого функцией
есть некоторые неясные для меня сведения о продлении срока службы объекта, возвращаемого из функции и связанного с ссылкой rvalue/const lvalue. Информация от здесь.
временная привязка к возвращаемому значению функции в операторе return не расширяется: она уничтожается сразу в конце возвращаемого выражения. Такая функция всегда возвращает висячую ссылку.
Если я правильно понимаю, quote утверждает, что время жизни объектов, возвращаемых операторами return, не может быть расширено. Но последнее предложение предполагает, что оно применяется только к функциям, возвращающим ссылки.
На GCC, из кода ниже я получаю следующий вывод:
struct Test
{
Test() { std::cout << "creationn"; }
~Test() { std::cout << "destructionn"; }
};
Test f()
{
return Test{};
}
int main()
{
std::cout << "before f calln";
Test && t = f();
std::cout << "after f calln";
}
before f call
creation
after f call
destruction
таким образом, похоже, что срок службы был продлен.
Следует ли продлевать срок службы временного объекта, связанного с такой ссылкой? Также не могли бы вы предоставить более четкий источник информации?
2 ответов
таким образом, похоже, что срок службы был продлен.
код довольно действителен, но обратите внимание, что объект, срок службы которого продлен, не является временным объектом, созданным внутри функции f()
by Test{}
, это возвращаемый объект функцией f()
. Этот возвращаемый объект строится из временного объекта, а затем привязывается к t
и срок службы продлевается. Кстати, возвращаемый объект возвращается по значению, и он является временным тоже.
для наблюдения вы можете добавить конструктор перемещения вручную:
struct Test
{
Test() { std::cout << "creation\n"; }
~Test() { std::cout << "destruction\n"; }
Test(Test&&) { std::cout << "move\n"; }
};
и компилировать и запускать с forbidding копировать elision режим, результат такой:
before f call
creation // the temporary created inside f
move // return object move-constructed
destruction // the temporary destroyed
after f call
destruction // the returned object destroyed
цитаты из стандарта, §15.2 / 6 временные объекты [класс.временный]:
временный, к которому привязана ссылка или что полное объект подобъект для к которой привязана ссылка сохраняется в течение всего срока ссылки, за исключением:
(6.1) временный объект, привязанный к ссылочному параметру в функции вызов сохраняется до завершения полного выражения, содержащего вызов.
(6.2) срок службы временной привязки к возвращаемому значению в оператор function return не расширяется; временное разрушается в конце полного выражения в операторе return.
(6.3) временная привязка к ссылке в новом инициализаторе сохраняется до завершения полного выражения, содержащего Нью-инициализатор. [ Пример:
struct S { int mi; const std::pair<int,int>& mp; }; S a { 1, {2,3} }; S* p = new S{ 1, {2,3} }; // Creates dangling reference
- end example ] [ Примечание: это может ввести висячую ссылку и реализациям рекомендуется в таком случае выдавать предупреждение. - конец Примечания ]
цитировать статьи GOTW
временный объект длится только до конца полного выражения, в котором он появляется. Однако C++ намеренно указывает, что привязка временного объекта к ссылке на const (или ссылку ravlue) в стеке удлиняет время жизни временного объекта до времени жизни самой ссылки и, таким образом, избегает того, что в противном случае было бы общей ошибкой висячей ссылки.
string f() { return "abc"; }
void g() {
const string& s = f();
cout << s << endl; // can we still use the "temporary" object?
}
в приведенном выше примере временное значение, возвращаемое f (), сохраняется до закрытия фигурной скобки. (Примечание это относится только к основе стека ссылок. Это не работает для ссылок, которые являются членами объектов.)
для юридического, читать это так ответ
ответ относится к и локальные ссылки const и ссылки rvalue