[basic.scope.pdecl] / 1 del borrador estándar de C ++ 20 tenía el siguiente ejemplo (no normativo) en una nota (cita parcial anterior a la fusión de la solicitud de extracción 3580 , consulte la respuesta a esta pregunta):
unsigned char x = x;
[...] x se inicializa con su propio valor (indeterminado).
¿Esto realmente tiene un comportamiento bien definido en C ++ 20?
En general, la autoinicialización de la forma T x = x;
tiene un comportamiento indefinido en virtud de que x
el valor de este es indeterminado antes de que se complete la inicialización. La evaluación de valores indeterminados generalmente causa un comportamiento indefinido ( [basic.indent] / 2 ), pero hay una excepción específica en [basic.indent] /2.3 que permite inicializar directamente una unsigned char
variable desde un unsigned char
valor l con valor indeterminado (causando la inicialización con un valor indeterminado )
Por lo tanto, esto por sí solo no causa un comportamiento indefinido, pero lo haría para otros tipos T
que no son tipos de caracteres estrechos sin signo o std::byte
, por ejemplo int x = x;
. Estas consideraciones también se aplicaron en C ++ 17 y antes, consulte también las preguntas vinculadas en la parte inferior.
Sin embargo, incluso para unsigned char x = x;
, el borrador actual [basic.lifetime] / 7 dice:
De manera similar, antes de que la vida útil de un objeto haya comenzado [...] a usar las propiedades del valor gl que no dependen de su valor está bien definido. El programa tiene un comportamiento indefinido si:
el valor gl se usa para acceder al objeto, o
[...]
Esto parece implicar que x
el valor en el ejemplo solo puede usarse durante su vida útil.
[basic.lifetime] / 1 dice:
[...]
La vida útil de un objeto de tipo T comienza cuando:
- [...] y
- su inicialización (si la hay) está completa (incluida la inicialización vacía) ([dcl.init]),
[...]
Así x
, la vida útil comienza solo después de que se completa la inicialización. Pero en el ejemplo citado x
, el valor se usa antes de que x
se complete la inicialización. Por lo tanto, el uso tiene un comportamiento indefinido.
¿Es correcto mi análisis? Si es así, ¿afecta a casos similares de uso antes de la inicialización, como
int x = (x = 1);
¿cuál, por lo que puedo decir, estaba bien definido en C ++ 17 y antes también?
Tenga en cuenta que en C ++ 17 (borrador final) el segundo requisito para que comience la vida útil fue diferente :
- si el objeto tiene una inicialización no vacía, su inicialización está completa,
Dado que x
tendría una inicialización vacía por la definición de C ++ 17 (pero no la del borrador actual), su vida útil ya habría comenzado cuando se accede al inicializador en los ejemplos dados anteriormente, por lo que en ambos ejemplos no hubo un comportamiento indefinido debido a la vida útil de x
en C ++ 17.
La redacción antes de C ++ 17 es nuevamente diferente, pero con el mismo resultado.
La pregunta no es sobre el comportamiento indefinido cuando se usan valores indeterminados, que se cubrieron, por ejemplo, en las siguientes preguntas:
int x ^= x;
no está sintácticamente bien formado. Puede tener una definición variable con inicializador (es decirint x = x;
, aunque sea UB) o una declaración de expresión de asignación xor (es decirx ^= x;
, aunque es UB six
es de tipoint
, se inicializó por defecto y no se asignó de antemano). No puedes mezclar estos dos en uno.Respuestas:
Esto se abrió como un problema editorial . Se envió al CWG para su discusión (interna). Aproximadamente 24 horas después, la persona que envió el problema creó una solicitud de extracción que modifica el ejemplo para dejar en claro que esto es UB:
Desde entonces, se agregó ese RP y se cerró el problema. Por lo tanto, parece claro que la interpretación obvia (UB debido al acceso a un objeto cuya vida útil no ha comenzado) es la interpretación prevista. Parece que la intención del comité es hacer que estas construcciones no funcionen, y el texto no normativo de la norma ha sido actualizado para reflejar esto.
fuente