[basic.scope.pdecl] / 1 стандартного проекту C ++ 20 мав наступний (ненормативний) приклад у примітці (часткова цитата до об'єднання запиту 3580 , див. відповідь на це запитання):
unsigned char x = x;
[...] x ініціалізується із власним (невизначеним) значенням.
Чи насправді це чітко визначена поведінка в С ++ 20?
Зазвичай самоініціалізація форми T x = x;
має невизначене поведінку в силу невизначеногоx
значення до того, як ініціалізація буде завершена. Оцінка невизначених значень, як правило, спричиняє невизначене поведінку ( [basic.indent] / 2 ), але в [basic.indent] /2.3 є специфічний виняток, який дозволяє безпосередньо ініціалізувати змінну від значення lva з невизначеним значенням (викликає ініціалізацію з невизначеним значенням ).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;
, хоча це x
тип UB, якщо він тип int
, був ініціалізований за замовчуванням і не призначений заздалегідь). Ви не можете змішати ці два в одне.