Временное время жизни в черновике N3290 C++

Пункт из черновика N3290 C++, § 12.2, 5-й пункт, строка 10.

Второй контекст — это когда ссылка привязана к временному объекту. Временный объект, к которому привязана ссылка, или временный объект, являющийся полным объектом подобъекта, к которому привязана ссылка, сохраняется в течение всего времени существования ссылки, за исключением:

Временная привязка к ссылке в новом-инициализаторе (5.3.4) сохраняется до завершения полного выражения, содержащего новый-инициализатор. [ Пример:

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

— конец примера ] [Примечание: это может привести к появлению висячей ссылки, и реализациям рекомендуется выдавать предупреждение в таком случае. — примечание в конце]

Это дополнительный момент по сравнению с C++03. Но пример для меня непонятен. Не могли бы вы пояснить этот момент на каком-нибудь другом примере?

Я знаю, что такое висячие ссылки и временные объекты, и что std::pair содержит два значения, возможно, разных типов данных.


person user751747    schedule 12.09.2011    source источник
comment
Обратите внимание, что RValue-refs (о чем, похоже, вы говорите) значительно менялись несколько раз по мере изменения стандарта. Если вы не используете FDIS (или, что еще лучше, фактический стандарт), вы все равно не увидите правильного объяснения.   -  person Billy ONeal    schedule 12.09.2011
comment
@Billy ONeal: этот текст остается таким, как показано в FDIS, и, хотя у меня нет доступа к окончательному стандарту, в FDIS не должно быть никаких изменений.   -  person David Rodríguez - dribeas    schedule 12.09.2011
comment
@David: Если это соответствует FDIS, то это должно быть правильно, да. (У меня нет доступа ни к FDIS, ни к окончательному стандарту на данный момент)   -  person Billy ONeal    schedule 12.09.2011


Ответы (1)


Temporaies в целом сохраняются только до конца выражения, в котором они были созданы:

#include <complex>


void func()
{
    std::complex<int>   a; // Real variable last until the end of scope.

    a = std::complex<int>(1,2) + std::complex<int>(3,4);
     // ^^^^^^^^^^^^^^^^^^^^^^  Creates a temporary object
     //                         This is destroyed at the end of the expression.
     // Also note the result of the addition creates a new temporary object
     // Then uses the assignment operator to change the variable 'a'
     // Both the above temporaries and the temporary returned by '+'
     // are destroyed at ';'

Если вы создаете временный объект и привязываете его к ссылке. Вы продлеваете его срок службы до того же срока службы ссылки, к которой он привязан.

    std::complex<int> const& b  = std::complex<int>(5,6);
                      //           ^^^^^^^^^^^^^^^^ Temporary object
                      // ^^^^                       Bound to a reference.
                      //                            Will live as long as b lives 
                      //                            (until end of scope)

Исключением из этого правила является случай, когда временный объект привязан к ссылке в новом инициализаторе.

    S* p1 = new S{ 1, {2,3} };
    // This is the new C++11 syntax that does the `equivalent off`:

    S* p2 = new S {1, std::pair<int,int>(2,3) };
                 //   ^^^^^^^^^^^^^^^^^^^^^^^    Temporary object.
                 //                              This lives until the end of the 
                 //                              expression that belongs to the new.
                 //                              ie the temporary will be destroyed
                 //                              when we get to the ';'

Но здесь мы привязываем новый временный объект к члену

const std::pair<int,int>& mp;

Это константная ссылка. Но временный объект, к которому он привязан, будет уничтожен в точке ';' в приведенном выше выражении, поэтому mp будет ссылкой на объект, который больше не существует, когда вы попытаетесь использовать его в последующих выражениях.

}
person Martin York    schedule 12.09.2011
comment
Итак, в просторечии вы могли бы сказать, что ссылки на члены класса не могут продлить время жизни временных объектов, прошедших через конструктор. Это хороший момент, чтобы забрать домой. Хороший ответ, кстати! - person Kerrek SB; 12.09.2011
comment
@Kerrek SB: Интересно, что цитата, кажется, указывает на обратное, ну, не совсем, но вроде как. Тот факт, что он упоминает только new-initializerаргумент конструктора в предыдущей строке, которая была вырезана из вопроса), вместе с отсутствием комментариев во второй Строка примера кода, по-видимому, указывает на то, что цель заключается в том, чтобы вторая строка не создавала оборванную ссылку. т.е. в стандарте ничего не сказано, что при агрегатной инициализации время жизни не продлевается. С другой стороны, и g++4.5, и clang++2.8 создают оборванную ссылку для этой второй строки. - person David Rodríguez - dribeas; 12.09.2011
comment
@ Дэвид: Ах, да. Значит, динамически размещаемые объекты не могут продлить время жизни временных объектов, не так ли? Это действительно имеет смысл. - person Kerrek SB; 12.09.2011
comment
@Kerrek SB: :) Еще немного сложнее, неагрегаты требуют использования конструктора, и это описано в пункте, который я отметил выше, и я даже не уверен в намерении этого конкретного изменения, но лучшее, что я могу придумать, это: только агрегаты без динамического хранилища могут продлить время жизни временного объекта, привязав постоянную ссылку могут указывает на то, что я не видел в стандарте ничего, что бы это запрещало, даже если компиляторы, к которым у меня есть доступ, этого не делают. - person David Rodríguez - dribeas; 12.09.2011
comment
Дэвид: Хммм. Если исключены только выражения new, то любое другое выражение, включая вызовы конструктора для автоматического выделения, должно быть включено в ситуации, продлевающие время жизни временного объекта. Стандарт вообще не касается этого? Я проведу несколько тестов с GCC, просто из любопытства. - person Kerrek SB; 12.09.2011
comment
На самом деле может случиться так, что вызовы конструктора в прямой инициализации не представляют собой привязку временного объекта к константной ссылке, а скорее временный объект существует только на время вызова конструктора. То есть тот факт, что сам вызов функции связывает свой аргумент с другой ссылкой на константу, не имеет отношения к исходному временному объекту. - person Kerrek SB; 12.09.2011
comment
@Kerrek: я думаю, что в этой ситуации мы привязываем временное значение к параметру, используемому в конструкторе (компилятор сгенерировал его). Таким образом, время жизни продлевается до времени жизни параметра (к сожалению, это не больше, чем временное, поэтому оно все равно уничтожается в конце области действия). Именно эту скрытую привязку пытается прояснить комментарий в стандарте, чтобы люди не думали, что она привязана непосредственно к члену и, таким образом, распространяется на время жизни объекта. - person Martin York; 12.09.2011