Використання змінної у власному ініціалізаторі


22

[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 charunsigned 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 знову відрізняється, але з тим же результатом.


Питання полягає не в невизначеному поведінці при використанні невизначених значень, що висвітлювалося, наприклад, у наступних питаннях:


@LanguageLawyer Я не впевнений, що я прав, особливо ні, якщо ще ніхто не відповів. Якщо інші збираються зі мною погодитися тут, я можу подати його пізніше (а може, хтось ще переді мною), але я не хочу подавати проблеми, в яких я не впевнений.
волоський горіх

@LanguageLawyer: Це не може бути проблемою редакції, якщо робочий документ однозначно говорить неправильну річ.
Оселедець Девіса

1
Слово змінюється P1358 .
xskxzr

1
@xskxzr Право, і в той же час LanguageLawyer також подав редакційне видання , яке, здається, було направлено CWG для роз'яснення наміру.
волоський горіх

1
@ clockw0rk int x ^= x;не синтаксично сформований. Ви можете мати визначення змінної з ініціалізатором (тобто int x = x;, хоча це UB) або вираз висловлення присвоєння xor (тобто x ^= x;, хоча це xтип UB, якщо він тип int, був ініціалізований за замовчуванням і не призначений заздалегідь). Ви не можете змішати ці два в одне.
волоський горіх

Відповіді:


8

Це було відкрито як редакційне питання . Він був переданий CWG для внутрішнього обговорення. Приблизно через 24 години особа, яка надіслала проблему, створила запит на витяг, який змінює приклад, щоб зрозуміти, що це UB:

Тут ініціалізація другого \ tcode {x} має невизначене поведінку, оскільки ініціалізатор отримує доступ до другого \ tcode {x} поза його життя \ iref {basic.life}.

Цей піар був доданий і питання закрите. Тож здається зрозумілим, що очевидна інтерпретація (UB через доступ до об'єкта, час життя якого не розпочався) - це призначене тлумачення. Здається, що комітет має намір зробити ці конструкції нефункціональними, а ненормативний текст стандарту було оновлено, щоб відобразити це.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.