Utilisation d'une variable dans son propre initialiseur

22

[basic.scope.pdecl] / 1 du projet de norme C ++ 20 contenait l' exemple (non normatif) suivant dans une note (citation partielle d'avant la fusion de la demande de tirage 3580 , voir la réponse à cette question):

unsigned char x = x;

[...] x est initialisé avec sa propre valeur (indéterminée).

Cela a-t-il réellement un comportement bien défini en C ++ 20?


Généralement, l'auto-initialisation du formulaire T x = x;a un comportement indéfini du fait que xla valeur de 'est indéterminée avant la fin de l'initialisation. L'évaluation de valeurs indéterminées provoque généralement un comportement indéfini ( [basic.indent] / 2 ), mais il existe une exception spécifique dans [basic.indent] /2.3 qui permet d'initialiser directement une unsigned charvariable à partir d'une valeur l unsigned charavec une valeur indéterminée (provoquant l'initialisation avec une valeur indéterminée) ).

Cela seul ne provoque donc pas de comportement indéfini, mais le serait pour d'autres types Tqui ne sont pas des types de caractères étroits non signés ou std::byte, par exemple int x = x;. Ces considérations s'appliquaient également en C ++ 17 et avant, voir également les questions liées en bas.

Cependant, même pour unsigned char x = x;, le projet actuel [basic.lifetime] / 7 dit:

De même, avant que la durée de vie d'un objet ne commence [...], l'utilisation des propriétés de la valeur gl qui ne dépendent pas de sa valeur est bien définie. Le programme a un comportement indéfini si:

  • la glvalue est utilisée pour accéder à l'objet, ou

  • [...]

Cela semble impliquer que xla valeur de dans l'exemple ne peut être utilisée que pendant sa durée de vie.

[basic.lifetime] / 1 dit:

[...]

La durée de vie d'un objet de type T commence lorsque:

  • [...] et
  • son initialisation (le cas échéant) est terminée (y compris l'initialisation vide) ([dcl.init]),

[...]

Ainsi, xla durée de vie ne commence qu'une fois l'initialisation terminée. Mais dans l'exemple cité, xla valeur est utilisée avant xla fin de l'initialisation. Par conséquent, l'utilisation a un comportement indéfini.

Mon analyse est-elle correcte et, dans l'affirmative, affecte-t-elle des cas similaires d'utilisation avant l'initialisation tels que

int x = (x = 1);

qui, pour autant que je sache, étaient bien définies en C ++ 17 et avant?


Notez qu'en C ++ 17 (version finale), la deuxième exigence de durée de vie pour commencer était différente :

  • si l'objet a une initialisation non vide, son initialisation est terminée,

Étant xdonné que l'initialisation serait vide par la définition de C ++ 17 (mais pas celle du projet actuel), sa durée de vie aurait déjà commencé lorsqu'elle est accessible dans l'initialiseur dans les exemples ci-dessus et donc dans les deux exemples, il n'y avait pas de comportement indéfini. en raison de la durée de vie de xC ++ 17.

La formulation avant C ++ 17 est à nouveau différente, mais avec le même résultat.


La question ne concerne pas un comportement indéfini lors de l'utilisation de valeurs indéterminées, qui a été couvert par exemple dans les questions suivantes:

noyer
la source
@LanguageLawyer Je ne suis pas sûr d'avoir raison, surtout pas si personne n'a encore répondu. Si d'autres sont d'accord avec moi ici, je pourrais en déposer un plus tard (ou peut-être que quelqu'un d'autre le fera avant moi), mais je ne veux pas signaler les problèmes dont je ne suis pas sûr.
noyer
@LanguageLawyer: Cela ne peut pas être un problème éditorial si le document de travail dit sans ambiguïté la mauvaise chose.
Davis Herring
1
Le mot est modifié par P1358 .
xskxzr
1
@xskxzr À droite, et dans l'intervalle, LanguageLawyer a également déposé un problème éditorial , qui semble avoir été transmis au CWG pour clarification de son intention.
noyer
1
@ clockw0rk int x ^= x;n'est pas bien formé syntaxiquement. Vous pouvez soit avoir une définition de variable avec initialiseur (c'est-à int x = x;- dire , bien qu'il soit UB), soit une instruction d'expression d'affectation xor (c'est x ^= x;-à- dire , bien qu'elle soit UB si elle xest de type int, a été initialisée par défaut et n'a pas été affectée à l'avance). Vous ne pouvez pas mélanger ces deux en un.
noyer

Réponses:

8

Cela a été ouvert comme un problème éditorial . Il a été transmis au CWG pour discussion (interne). Environ 24 heures plus tard, la personne qui a transmis le problème a créé une demande d'extraction qui modifie l'exemple pour indiquer clairement qu'il s'agit de l'UB:

Ici, l'initialisation du second \ tcode {x} a un comportement indéfini, car l'initialiseur accède au second \ tcode {x} en dehors de sa durée de vie \ iref {basic.life}.

Ce RP a depuis été ajouté et le problème est clos. Il semble donc clair que l'interprétation évidente (UB due à l'accès à un objet dont la durée de vie n'a pas commencé) est l'interprétation voulue. Il semble que l'intention du comité soit de rendre ces concepts non fonctionnels, et le texte non normatif de la norme a été mis à jour pour refléter cela.

Nicol Bolas
la source