Uso della variabile nel proprio inizializzatore


22

[basic.scope.pdecl] / 1 della bozza standard C ++ 20 conteneva il seguente esempio (non normativo) in una nota (citazione parziale precedente alla fusione della richiesta pull 3580 , vedere la risposta a questa domanda):

unsigned char x = x;

[...] x è inizializzato con il suo valore (indeterminato).

Questo ha effettivamente un comportamento ben definito in C ++ 20?


Generalmente l'autoinizializzazione della forma T x = x;ha un comportamento indefinito in quanto xil valore è indeterminato prima che l'inizializzazione sia completata. La valutazione di valori indeterminati provoca generalmente un comportamento indefinito ( [basic.indent] / 2 ), ma esiste un'eccezione specifica in [basic.indent] /2.3 che consente di inizializzare direttamente una unsigned charvariabile da un valore unsigned charcon valore indeterminato (causando l'inizializzazione con un valore indeterminato ).

Questo da solo non causa quindi un comportamento indefinito, ma lo farebbe per altri tipi Tche non sono tipi di caratteri stretti non firmati o std::byte, ad es int x = x;. Queste considerazioni sono state applicate in C ++ 17 e anche prima, vedi anche le domande collegate in fondo.

Tuttavia, anche per unsigned char x = x;, l'attuale bozza [basic.lifetime] / 7 dice:

Allo stesso modo, prima che la durata di un oggetto sia iniziata [...] usando le proprietà del valore glue che non dipendono dal suo valore è ben definita. Il programma ha un comportamento indefinito se:

  • il valore gluteo viene utilizzato per accedere all'oggetto, oppure

  • [...]

Ciò sembra implicare che xil valore nell'esempio possa essere utilizzato solo durante la sua vita.

[basic.lifetime] / 1 dice:

[...]

La durata di un oggetto di tipo T inizia quando:

  • [...] e
  • la sua inizializzazione (se presente) è completa (inclusa l'inizializzazione vacua) ([dcl.init]),

[...]

Così x's vita inizia solo dopo l'inizializzazione è stata completata. Ma nell'esempio citato xviene usato il valore prima che xl'inizializzazione sia completa. Pertanto l'uso ha un comportamento indefinito.

La mia analisi è corretta e, se lo è, influisce su casi simili di utilizzo prima dell'inizializzazione come

int x = (x = 1);

quali, per quanto posso dire, erano ben definiti in C ++ 17 e anche prima?


Si noti che in C ++ 17 (bozza finale) il secondo requisito per l'inizio della vita era diverso :

  • se l'oggetto ha un'inizializzazione non vacua, l'inizializzazione è completa,

Poiché xavrebbe un'inizializzazione vacua secondo la definizione di C ++ 17 (ma non quella nella bozza corrente), la sua vita sarebbe già iniziata quando si accedeva all'inizializzatore negli esempi sopra riportati e quindi in entrambi gli esempi non c'era un comportamento indefinito a causa della durata di xin C ++ 17.

La formulazione precedente a C ++ 17 è di nuovo diversa, ma con lo stesso risultato.


La domanda non riguarda il comportamento indefinito quando si usano valori indeterminati, che è stato trattato ad esempio nelle seguenti domande:


@LanguageLawyer Non sono sicuro di avere ragione, soprattutto se nessuno ha ancora risposto. Se altri sono d'accordo con me qui, potrei presentare uno in seguito (o forse qualcun altro lo farà prima di me), ma non voglio presentare problemi di cui non sono sicuro.
noce,

@LanguageLawyer: Non può essere un problema editoriale se il documento di lavoro dice in modo inequivocabile la cosa sbagliata.
Davis Herring,

1
La parola è cambiata da P1358 .
xskxzr,

1
@xskxzr Bene, e nel frattempo LanguageLawyer ha anche presentato un problema editoriale , che sembra essere stato inoltrato a CWG per chiarimenti di intenzione.
noce,

1
@ clockw0rk int x ^= x;non è sintatticamente ben formato. Puoi avere una definizione di variabile con l'inizializzatore (cioè int x = x;, sebbene sia UB) o un'istruzione di espressione di assegnazione xor (cioè x ^= x;, sebbene sia UB se xè di tipo int, è stata inizializzata di default e non assegnata in precedenza). Non puoi mescolare questi due in uno.
noce

Risposte:


8

Questo è stato aperto come un problema editoriale . È stato inoltrato al CWG per la discussione (interna). Circa 24 ore dopo, la persona che ha inoltrato il problema ha creato una richiesta pull che modifica l'esempio per chiarire che si tratta di UB:

Qui, l'inizializzazione del secondo \ tcode {x} ha un comportamento indefinito, poiché l'inizializzatore accede al secondo \ tcode {x} al di fuori della sua vita \ iref {basic.life}.

Quel PR è stato aggiunto e il problema è stato chiuso. Quindi sembra chiaro che l'interpretazione ovvia (UB dovuta all'accesso a un oggetto la cui durata non è iniziata) è l'interpretazione prevista. Sembra che l'intenzione del comitato sia di rendere questi costrutti non funzionali, e il testo non normativo dello standard è stato aggiornato per riflettere questo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.