Чего мне не хватает в стандарте C ++ 11?

Я не спорю с результатом приведенного ниже кода, поскольку считаю правильным предположить, что и ссылка на константное значение, и ссылка на 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';
}

2

Решение

Второй контекст, когда ссылка связана с временным — Кроме — Время жизни временной привязки к возвращенному значению в операторе возврата функции не расширенный

A f() { A a; return a; }

Прежде всего, a не временный Это может быть то, о чем вы думали:

A f() { return A(); }

Во-вторых, возвращаемый тип функции не является ссылочным типом. Вот когда правило будет применяться:

const A& f() { return A(); }

Временный от A() привязывается к типу возврата const A&, Как правило, срок службы временного не продлевается.

4

Другие решения

Упомянутая вами цитата специально предназначена для возврата ссылки из функции и привязки этой ссылки к временному:

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()
5

По вопросам рекламы [email protected]