Какая стандартная формулировка говорит нам, что временное продление срока службы ref-to-const только «работает один раз»?
Мне был показан следующий пример в чате:
#include 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
в этой области.
- HttpWebRequest и проверка подлинности форм в C #
- Есть ли причина использовать ключевое слово auto для C ++ 03?
- Сколько памяти будет освобождено, если указатель изменится на C?
- Должен ли я использовать байт или int?
- Async Task.WhenAll с таймаутом
Предположительно, тогда продление жизни только «работает один раз»; то есть он применяется, когда аргументы func
инициализируются, но не передаются через последовательные привязки.
Является ли моя интерпретация правильной? Если это так (и если какой-либо отдельный параграф применим непосредственно), то какая стандартная формулировка определяет это поведение?
- Макро против функции в C
- Добавить элемент в элемент управления Listview
- Очень большая коллекция в .Net вызывает исключение из памяти
- Преобразование cv :: Mat в IplImage *
- Противоположность Intersect ()
- Почему аргумент copy-constructor const?
- Ограничивает ли Parallel.ForEach количество активных streamов?
- Оценка координат узлов узлов
Это вопрос двух отчетов о проблемах: 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) сохраняется до завершения полного выражения, содержащего вызов.
Противоречит другим правилам в том же параграфе. Поскольку временный обязан как опорного параметра в вызове функции и к локальной автоматической контрольной переменной.
Ты почти прав. Такое поведение на самом деле происходит от вызова функции специально, а не из-за какого-либо правила «только работает один раз».
Вот формулировка для всей функции расширения продолжительности жизни, с соответствующим правилом, выделенным жирным шрифтом:
[C++11: 12.2/5]:
[..] Временная привязка ссылки или временный объект, являющийся полным объектом подобъекта, к которому привязана ссылка, сохраняется для ресурса ссылки, за исключением :
- [..]
- Временная привязка к эталонному параметру в вызове функции (5.2.2) сохраняется до завершения полного выражения, содержащего вызов.
- [..]
Правило, которое здесь применяется, является здравым смыслом. Стандарт плохо сформулирован и на самом деле гарантирует это. Но практического способа его реализации нет.
Наверное, я немного замедлился, но для меня не стало ясно, каково решение этого вопроса от чтения других ответов. Таким образом, я изменил показанный код и хотел обобщить для других: ответ заключается в том, что вы получаете неопределенное поведение, если вы обращаетесь к 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
строка main 2
- это неопределенное поведение .