Как бы авто & amp; продлить срок службы временного объекта?

Код ниже иллюстрирует мою озабоченность:

#include <iostream>struct O
{
~O()
{
std::cout << "~O()\n";
}
};

struct wrapper
{
O const& val;

~wrapper()
{
std::cout << "~wrapper()\n";
}
};

struct wrapperEx // with explicit ctor
{
O const& val;

explicit wrapperEx(O const& val)
: val(val)
{}

~wrapperEx()
{
std::cout << "~wrapperEx()\n";
}
};

template<class T>
T&& f(T&& t)
{
return std::forward<T>(t);
}int main()
{
std::cout << "case 1-----------\n";
{
auto&& a = wrapper{O()};
std::cout << "end-scope\n";
}
std::cout << "case 2-----------\n";
{
auto a = wrapper{O()};
std::cout << "end-scope\n";
}
std::cout << "case 3-----------\n";
{
auto&& a = wrapper{f(O())};
std::cout << "end-scope\n";
}
std::cout << "case Ex-----------\n";
{
auto&& a = wrapperEx{O()};
std::cout << "end-scope\n";
}
return 0;
}

Смотрите это в прямом эфире Вот.

Говорят, что auto&& продлит время жизни временного объекта, но я не могу найти стандартные слова для этого правила, по крайней мере, в N3690.

Наиболее актуальным может быть раздел 12.2.5 о временном объекте, но не совсем то, что я ищу.

Итак, будет авто&& правило продления жизни все временные объекты, участвующие в выражении, или только конечный результат?

Более конкретно, это a.val гарантированно будет действительным (не висят), прежде чем мы достигнем конца области в случае 1?

Редактировать:
Я обновил пример, чтобы показать больше случаев (3 & Ex).

Вы увидите, что только в случае 1 время жизни O увеличивается.

10

Решение

Точно так же, как ссылка на const делает:

const auto& a = wrapper{O()};

или же

const wrapper& a = wrapper{O()};

или также

wrapper&& a = wrapper{O()};

Более конкретно, это a.val гарантированно будет действительным (не висят), прежде чем мы достигнем конца области в случае 1?

Да, это.

Нет ничего особенно важного auto Вот. Это просто местодержатель для правильного типа (wrapper) который выводится компилятором. Основным моментом является тот факт, что временный привязан к ссылке.

Для более подробной информации смотрите Кандидат на звание самого важного которые я цитирую:

Обычно временный объект длится только до конца полного выражения, в котором он появляется. Однако в C ++ специально указывается, что привязка временного объекта к ссылке на const в стеке удлиняет время жизни временного объекта до времени жизни самой ссылки.

Эта статья о C ++ 03, но аргумент все еще действителен: временный объект может быть связан со ссылкой на const (но не на ссылку на неconst). В C ++ 11 временная банка также быть привязанным к rvalue ссылке. В обоих случаях время жизни временного объекта увеличивается до времени жизни ссылки.

Соответствующие части Стандарта C ++ 11 в точности соответствуют тем, которые упоминаются в OP, то есть 12.2 p4 и p5:

4 — Существуют два контекста, в которых временные
другая точка, чем конец полного выражения. Первый контекст
является […]

5 — Второй контекст, когда ссылка связана с временным. […]

(Есть некоторые исключения в пунктах маркера после этих строк.)

Обновить: (После комментария техасбруса.)

Причина, почему O в случае 2 имеет короткий срок службы, что у нас есть auto a = wrapper{O()}; (видите, нет & здесь), а затем временный не привязан к ссылке. Временный, на самом деле, копируется в a используя сгенерированный компилятором конструктор копирования. Следовательно, время жизни временного элемента не увеличивается, и оно умирает в конце полного выражения, в котором оно появляется.

В этом конкретном примере есть опасность, потому что wrapper::val это ссылка. Компилятор сгенерировал copy-конструктор wrapper будет связывать a.val к тому же объекту, что временный val участник обязан. Этот объект также является временным, но имеет тип O, Затем, когда этот последний временный умирает, мы видим ~O() на экране и a.val болтается!

Сравните случай 2 с этим:

std::cout << "case 3-----------\n";
{
O o;
auto a = wrapper{o};
std::cout << "end-scope\n";
}

Вывод (при компиляции с gcc с использованием опции -fno-elide-constructors)

case 3-----------
~wrapper()
end-scope
~wrapper()
~O()

Сейчас временный wrapper имеет свой val член связан с o, Заметить, что o не временный. Как я сказал, a является копией wrapper временный и a.val также связывает с
o, Прежде чем сфера действия заканчивается временным wrapper умирает и мы видим первый ~wrapper() на экране.

Тогда сфера заканчивается, и мы получаем end-scope, Сейчас, a а также o должны быть уничтожены в обратном порядке строительства, следовательно, мы видим ~wrapper() когда a умирает и наконец ~O() когда это oпора Это показывает, что a.val не болтается

(Последнее замечание: я использовал -fno-elide-constructors предотвратить оптимизацию, связанную с копированием, которая усложнит обсуждение здесь, но это другое история.)

5

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

Других решений пока нет …

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