Страницы

Поиск по вопросам

понедельник, 9 декабря 2019 г.

Продление жизни значения константной ссылкой

#cpp #шаблоны_с++ #ссылки #language_lawyer #неопределенное_поведение


Как известно, если rvalue передаётся в некую функцию через константную ссылку, то
время его жизни продлевается. Т. е. в следующем примере оно точно живёт пока выполняется
функция ref_to_ptr. Вопрос в том, насколько долго обязано жить такое значение и допустимо
ли его использование в функции print, либо же это UB с разыменованием потенциально
мусорного указателя?

https://ideone.com/CcacHz

#include 

using 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 приведу такой код: #include using 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, но сразу же после него.

Комментариев нет:

Отправить комментарий