[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 x
il 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 char
variabile da un valore unsigned char
con valore indeterminato (causando l'inizializzazione con un valore indeterminato ).
Questo da solo non causa quindi un comportamento indefinito, ma lo farebbe per altri tipi T
che 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 x
il 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 x
viene usato il valore prima che x
l'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é x
avrebbe 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 x
in 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:
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.