Я не спорю с результатом приведенного ниже кода, поскольку считаю правильным предположить, что и ссылка на константное значение, и ссылка на rvalue продлевают время жизни временного значения, возвращаемого функцией. Что меня удивляет, так это абзац в Стандарте, который, кажется, говорит об обратном:
12.2p5 (выделено мое):
Второй контекст, когда ссылка связана с временным.
временный, к которому привязана ссылка, или временный, который является
завершенный объект подобъекта, к которому привязана ссылка
сохраняется в течение всей жизни ссылки Кроме:
- …
- …
- Время жизни временной привязки к возвращенному значению в функции
оператор возврата (6.6.3) не продлен; временное уничтожено
в конце полного выражения в операторе возврата.
Пример кода:
#include <iostream>
struct A{ A() : i(2) {} int i;};
A f() { A a; return a; }
int main()
{
A&& a1 = f();
std::cout << a1.i << '\n';
const A& a2 = f();
std::cout << a2.i << '\n';
}
Второй контекст, когда ссылка связана с временным — Кроме — Время жизни временной привязки к возвращенному значению в операторе возврата функции не расширенный
A f() { A a; return a; }
Прежде всего, a
не временный Это может быть то, о чем вы думали:
A f() { return A(); }
Во-вторых, возвращаемый тип функции не является ссылочным типом. Вот когда правило будет применяться:
const A& f() { return A(); }
Временный от A()
привязывается к типу возврата const A&
, Как правило, срок службы временного не продлевается.
Упомянутая вами цитата специально предназначена для возврата ссылки из функции и привязки этой ссылки к временному:
const T& f() { return T(); };
Это не так в вашем коде, потому что вы привязываете временную ссылку к ссылке на стороне вызова, а не в операторе возврата. В ваших комментариях вы упоминаете, что когда вы изменяете код на:
T f() { return T(); }
T&& r = f();
срок службы еще продлен, но это неправильно. Временные жизни на время return
оператор, во время которого он копируется в возвращаемое значение. После завершения копирования время жизни временного заканчивается. На вызывающей стороне у вас есть другой временный (результат f()
) чья жизнь увеличивается
Но нет никаких сомнений в том, что срок службы временных Если вы определите деструктор для класса A с любым сообщением, оно будет напечатано в конце main (), или есть?
Это утверждение также неверно. Вы видите результаты оптимизации возвращаемого значения (RVO). Вместо создания временного для T()
внутри функции и другого для возвращаемого значения компилятор создает два объекта в одном месте. Вы, вероятно, видите один объект в выводе программы, но в теории их два.
Вы можете попробовать использовать g ++ с -fno-elide-constructors, и вы сможете увидеть оба временных значения, одно из которых будет расширено, а другое — нет.
Кроме того, вы можете вернуть ссылку:
const A& f() { return A(); }
const A& r = f();
Который должен показать, как временный умирает раньше r
выходит за рамки.
Это в основном тот же тест, подавляющий
$ g ++ —version | голова -1
g ++ (GCC) 4.3.2
$ cat x.cpp
#include <iostream>
struct X {
X() { std::cout << "X\n"; }
~X() { std::cout << "~X\n"; }
};
X f() { return X(); }
int main() {
const X& x = f();
std::cout << "still in main()\n";
}
$ g ++ -o t1 x.cpp && ./t1
X
still in main()
~X
$ g ++ -fno-elide-constructors -o t2 x.cpp && ./t2
X
~X
still in main()
~X
$ clang ++ -version | голова -1
$ clang версия 3.2 (теги / RELEASE_32 / финал)
$ clang ++ -fno-elide-constructors -o t3 x.cpp && ./t3
X
~X
still in main()
~X
$ cat y.cpp
#include <iostream>
struct X {
X() { std::cout << "X\n"; }
~X() { std::cout << "~X\n"; }
};
const X& f() { return X(); }
int main() {
const X& x = f();
std::cout << "still in main()\n";
}
$ g ++ -fno-elide-constructors -o t4 y.cpp && ./t4
X
~X
still in main()