[basic.scope.pdecl] / 1 стандартного черновика C ++ 20 содержал в примечании следующий (ненормативный) пример (частичная цитата до запроса на объединение 3580 , см. ответ на этот вопрос):
unsigned char x = x;
[...] x инициализируется своим собственным (неопределенным) значением.
Это на самом деле имеет четко определенное поведение в C ++ 20?
Обычно самоинициализация формы T x = x;
имеет неопределенное поведение в силу неопределенностиx
значения до завершения инициализации. Оценка неопределенных значений обычно вызывает неопределенное поведение ( [basic.indent] / 2 ), но в [basic.indent] /2.3 есть специальное исключение, которое позволяет напрямую инициализировать переменную из lvalue с неопределенным значением (вызывая инициализацию с неопределенным значением) ).unsigned char
unsigned char
Это само по себе, следовательно, не вызывает неопределенного поведения, но будет для других типов T
, которые не являются беззнаковыми узкими символьными типами или std::byte
, например int x = x;
. Эти соображения применяются в C ++ 17 и ранее, см. Также связанные вопросы внизу.
Однако даже для unsigned char x = x;
текущего проекта [basic.lifetime] / 7 говорится:
Точно так же до того, как время жизни объекта началось [...], свойства glvalue, которые не зависят от его значения, четко определены. Программа имеет неопределенное поведение, если:
glvalue используется для доступа к объекту, или
[...]
Кажется, это подразумевает, что x
значение в примере может использоваться только в течение его времени жизни.
[basic.lifetime] / 1 говорит:
[...]
Время жизни объекта типа T начинается, когда:
- [...] а также
- его инициализация (если есть) завершена (включая пустую инициализацию) ([dcl.init]),
[...]
Таким образом x
, время жизни начинается только после завершения инициализации. Но в приведенном примере x
значение используется до x
завершения инициализации. Поэтому использование имеет неопределенное поведение.
Является ли мой анализ правильным и влияет ли он на подобные случаи использования перед инициализацией, такие как
int x = (x = 1);
которые, насколько я могу судить, были четко определены в C ++ 17 и ранее?
Обратите внимание, что в C ++ 17 (окончательный вариант) второе требование для начала жизни было другим :
- если объект имеет не пустую инициализацию, его инициализация завершена,
Так x
как инициализация была бы бессодержательной по определению C ++ 17 (но не по текущему проекту), его время жизни уже началось бы, когда к нему обращались в инициализаторе в приведенных выше примерах, и поэтому в обоих примерах не было неопределенного поведения из-за времени жизни x
в C ++ 17.
Формулировка до C ++ 17 снова отличается, но с тем же результатом.
Вопрос не о неопределенном поведении при использовании неопределенных значений, который был рассмотрен, например, в следующих вопросах:
источник
int x ^= x;
не является синтаксически правильно сформированным. Вы можете иметь определение переменной с инициализатором (т.int x = x;
Е. Хотя это UB) или оператор выражения присваивания xor (т.x ^= x;
Е. Хотя это UB, если онx
имеет типint
, инициализирован по умолчанию и не назначен заранее). Вы не можете смешать эти два в одно.Ответы:
Это было открыто как редакционная проблема . Он был направлен в CWG для (внутреннего) обсуждения. Примерно через 24 часа человек, который направил проблему, создал запрос на извлечение, который модифицирует пример, чтобы прояснить, что это UB:
Этот PR был добавлен, и проблема закрыта. Таким образом, кажется очевидным, что очевидная интерпретация (UB из-за доступа к объекту, время жизни которого еще не началось) является предполагаемой интерпретацией. Похоже, что целью комитета является сделать эти конструкции не функциональными, и ненормативный текст стандарта был обновлен, чтобы отразить это.
источник