Подтвердить что ты не робот

Какая стандартная формулировка говорит нам, что временное продление срока службы ref-to-const только "работает один раз"?

Мне был показан следующий пример в чате:

#include <iostream>
struct foo { ~foo() { std::cout << "destroying!\n"; } };
const foo& func(const foo& a, const foo&) { return a; }

int main()
{
  foo x;
  const foo& y = func(foo(), x);
  std::cout << "main\n";
}

Выход:

destroying!
main
destroying!

Похоже, что время жизни временного файла foo не распространяется на полноту main, хотя оно привязано к ref-to-const в этой области.

Предположительно, тогда расширение продолжительности жизни "работает только один раз"; то есть он применяется, когда аргументы func инициализируются, но не передаются через последовательные привязки.

Является ли моя интерпретация правильной? Если это так (и если какой-либо отдельный параграф применим непосредственно), то какая стандартная формулировка определяет это поведение?

4b9b3361

Ответ 1

Это тема двух отчетов о проблемах, http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1299 и http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1568.

Первый отчет о проблеме, который я являюсь репортером, должен был охватывать все эти случаи, когда ссылка привязана к временному объекту, но не предназначена для продления срока службы. Описание в теле проблемы только упоминает, что prvalues ​​путают с временными выражениями (которые фактически решают, продлевается ли продолжительность жизни того, что они оценивают, или нет). Но lvalue и xvalues ​​также смешиваются с ними в Стандарте. Пример, где это происходит в контексте static_cast, - номер выпуска № 1568 (в котором использование "временной переменной" еще больше смущает вопрос).

Собственно, это:

Временная привязка к эталонному параметру в вызове функции (5.2.2) сохраняется до завершения полного выражения, содержащего вызов.

Противоречит другим правилам в том же параграфе. Поскольку временный обязан как опорного параметра в вызове функции и к локальной автоматической контрольной переменной.

Ответ 2

Ты почти прав. Такое поведение на самом деле происходит от вызова функции, а не из-за какого-либо правила "только работает один раз".

Здесь формулировка для всей функции расширения продолжительности жизни, с соответствующим правилом, выделенным жирным шрифтом:

[C++11: 12.2/5]: [..] Временная привязка ссылки или временный объект, являющийся полным объектом подобъекта, к которому привязана ссылка, сохраняется для ресурса ссылки кроме

  • [..]
  • Временная привязка к ссылочному параметру в вызове функции (5.2.2) сохраняется до завершения полного выражения, содержащего вызов.
  • [..]

Ответ 3

Применяемое здесь правило - здравый смысл. Стандарт плохо сформулированные и на самом деле гарантируют это. Но нет практический способ ее реализации.

Ответ 4

Возможно, я немного медленный, но для меня не стало ясно, что разрешение этого вопроса - от чтения других ответов. Таким образом, я изменил показанный код и хотел обобщить для других: ответ: вы получаете undefined поведение, если вы обращаетесь к y!

Запустите этот код:

struct foo {
    int id;
    foo(int id) : id(id) { std::cout << "ctor " << id << std::endl; };
    ~foo() { std::cout << "dtor " << id << std::endl; }
};
const foo& func(const foo& a, const foo&) { return a; }

int main(int argc, char** argv) {
    foo x(1);
    const foo& y = func(foo(2), x);
    std::cout << "main " << y.id << std::endl;
    return 0;
}

Выход для меня:

ctor 1
ctor 2
dtor 2
main 2
dtor 1

Но строка main 2 - это undefined поведение.