Ответ 1
LONG STORY, SHORT
Компилятор не может продлить время жизни временного объектаnew A { "temporary " }
, поскольку созданныйA
и временный, имеет разные сроки хранения.
Подтверждение того, что говорит Стандарт, можно найти в конце этого сообщения. В Стандарте явно говорится, что срок жизни не будет расширен, но он не вдавается в подробности, почему это так.
Этот пост попробует объяснить причину таким образом, который понятен для более широкой аудитории, а не только в среднем language-lawyer.
Введение
В С++ существует несколько типов различных длительностей хранения, которые могут иметь объекты, в том числе продолжительность автоматического и динамического хранения, которые кратко описаны ниже:
Время автоматического хранения
Хранилище для объекта с автоматической продолжительностью хранения будет сохраняться до тех пор, пока не завершится создание блока, в котором они созданы.
-
Объекты, объявленные в области блока, имеют автоматическую продолжительность хранения (если они не объявлены
static
илиextern
, но неregister
). -
Временные ряды по определению объявляются в блочной области, поэтому они также имеют автоматическую продолжительность хранения.
Динамическое время хранения
Хранилище для объекта с динамической продолжительностью хранения будет сохраняться до тех пор, пока не будет указано, что он должен быть выпущен; Другими словами, такое хранилище не связано с какой-либо конкретной областью.
-
Объекты, созданные динамически через
operator new
, имеют, как указано, динамическую продолжительность хранения.Хранилище будет сохраняться до тех пор, пока не будет выполнен соответствующий вызов
operator delete
.
Агрегатная инициализация с автоматическим временем хранения
Как указано в предыдущем разделе, временная автоматизированная продолжительность хранения.
Если мы построим агрегат с автоматической продолжительностью хранения, это тоже будет иметь привязанность к текущей области; это означает, что время жизни временного объекта может быть легко расширено, чтобы соответствовать сумме совокупности.
Примечание. Мы можем представить, что они живут в одной и той же "коробке", и в конце области действия мы отбрасываем эту коробку, что прекрасно; ни временная, ни совокупность не переживут время жизни коробки.
Наша реализация (A)
struct A { std::string const& ref; };
void func () {
A x { {"hello world"} };
}
За кулисами (A)
Поскольку и x
, и временные, имеют автоматическую продолжительность хранения, компилятор может реализовать эту функцию как следующий, семантически эквивалентный, фрагмент:
void __func () {
std::string __unnamed_temporary { "hello world" };
A x { __unnamed_temporary };
}
Примечание: и временное, и агрегатное время жизни привязаны к текущей области, awesome!
Агрегатная инициализация с динамической продолжительностью хранения
Наша реализация (B)
A* gunc () {
A * ptr = new A { { "hello world" } };
return ptr;
}
int main () {
A * p = gunc ();
std::cout << p->ref << std::endl; // DANGER, WILL ROBINSON!
delete p;
}
В предыдущих разделах было указано, что временные файлы имеют автоматическую продолжительность хранения, что означает, что наш временный, привязанный к A::ref
, будет построен на хранилище, которое находится в текущей области.
За сценой (B)
Семантическая эквивалентность gunc
может выглядеть как реализация ниже:
A* gunc () {
A __unnamed_temporary { "hello world " };
A * ptr = new A { __unnamed_temporary }; // (1)
return ptr;
}
Вы тоже это думаете, не так ли?
Мы больше не можем продлить время жизни нашего временного, чтобы соответствовать времени A
, созданному с динамической продолжительностью хранения, в (1).
Проблема заключается в том, что автоматическое хранилище для __unnamed_temporary
исчезнет, как только мы вернемся из gunc
, эффективно убив наш временный.
Динамически созданный A
, тем не менее, останется живым, оставив нас с обвисшей ссылкой в main
.
Заключение
Компилятор не может продлить время жизни любых временных объектов, связанных с созданием объекта через новый-инициализатор, потому что новый объект и временные файлы будут иметь разную продолжительность хранения.
Что означает стандарт (n3797)?
12.2p5
Временные объекты[class.temporary]
Временная привязка ссылки или временный объект, являющийся полным объектом подобъекта, к которому привязана ссылка, сохраняется для времени жизни ссылки, за исключением:
...
Временная привязка к ссылке в new-initializer (5.3.4) сохраняется до завершения полного выражения, содержащего новый-инициализатор.
[Примечание. Это может привести к обманутой ссылке, и в этом случае рекомендуется внедрить предупреждение. - конец примечания]