#cpp #шаблоны_с++ #ссылки #language_lawyer #неопределенное_поведение
Как известно, если rvalue передаётся в некую функцию через константную ссылку, то время его жизни продлевается. Т. е. в следующем примере оно точно живёт пока выполняется функция ref_to_ptr. Вопрос в том, насколько долго обязано жить такое значение и допустимо ли его использование в функции print, либо же это UB с разыменованием потенциально мусорного указателя? https://ideone.com/CcacHz #includeusing namespace std; template const T *ref_to_ptr(const T &x) { return &x; } void print(const int *val) { cout << *val << endl; } int main() { print(ref_to_ptr(42)); return 0; }
Ответы
Ответ 1
Насколько я понимаю стандарт (цитата): ⁴ [...] Temporary objects are destroyed as the last step in evaluating the full-expression that (lexically) contains the point where they were created. [...] ⁵ There are three contexts in which temporaries are destroyed at a different point than the end of the full-expression. [...] ⁶ The third context is when a reference is bound to a temporary object. The temporary object to which the reference is bound or the temporary object that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference [...] The exceptions to this lifetime rule are: (6.9) — A temporary object bound to a reference parameter in a function call persists until the completion of the full-expression containing the call. (6.10) — The lifetime of a temporary bound to the returned value in a function return statement is not extended; the temporary is destroyed at the end of the full-expression in the return statement. Иными словами: обычно временный объект, на который ссылается ссылка, умирает вместе со ссылкой. Но если вы передаёте в функцию временный объект как аргумент для ref-параметра, время жизни этого временного объекта продлевается до конца всего выражения, содержащего вызов функции. Это значит, что время жизни параметра x заканчивается в конце строки print(ref_to_ptr(42)); то есть доступа к «умершему» объекту нет. Это также, судя по всему, означает, что переписав код следующим образом: const int *ptr = ref_to_ptr(42); print(ptr); вы получите таки undefined behaviour, т. к. время жизни временного объекта, на который указывает ptr, заканчивается после первой строки!Ответ 2
Добавлю критерий истины :) - практику. В подтверждение точки зрения @VladD приведу такой код: #includeusing namespace std; template const T *ref_to_ptr(const T &x) { return &x; } class Test { public: Test() { cout << "ctor: " << this << endl; } ~Test() { cout << "dtor: " << this << endl; } }; void print(const Test * val) { cout << val << endl; } int main() { print(ref_to_ptr(Test())); const Test * ptr = ref_to_ptr(Test()); print(ptr); cout << "The end.\n"; return 0; } Сей код ведет себя одинаково в VC++ и в GCC, демонстрируя, что временный объект умирает уже после вызова print, но сразу же после него.
Комментариев нет:
Отправить комментарий