Lo standard C ++ è cambiato rispetto all’uso di valori indeterminati e comportamento indefinito in C ++ 14?

Come indicato in L’inizializzazione comporta la conversione da lvalue a valore? È int x = x; UB? lo standard C ++ ha un sorprendente esempio nella sezione 3.3.2 Punto di dichiarazione in cui un int è inizializzato con il proprio valore indeterminato:

 int x = 12; { int x = x; } 

Qui la seconda x è inizializzata con il proprio valore (indeterminato). – esempio finale ]

La risposta di Johannes a questa domanda indica un comportamento indefinito poiché richiede una conversione da lvalue a rvalue.

Nell’ultimo standard N3936 bozza di C ++ 14 che può essere trovato qui, questo esempio è stato modificato in:

 unsigned char x = 12; { unsigned char x = x; } 

Qui la seconda x è inizializzata con il proprio valore (indeterminato). – esempio finale ]

Qualcosa è cambiato in C ++ 14 rispetto ai valori indeterminati e al comportamento non definito che ha guidato questa modifica nell’esempio?

Sì, questo cambiamento è stato determinato da cambiamenti nel linguaggio che rendono il comportamento non definito se un valore indeterminato viene prodotto da una valutazione ma con alcune eccezioni per i caratteri stretti senza segno .

Il rapporto sui difetti 1787 cui testo proposto può essere trovato in N3914 1 è stato recentemente accettato nel 2014 ed è incorporato nell’ultima bozza di lavoro N3936 :

Il cambiamento più interessante rispetto ai valori indeterminati sarebbe la sezione 8.5 paragrafo 12 che va da:

Se non è specificato alcun inizializzatore per un object, l’object viene inizializzato di default; se non viene eseguita alcuna inizializzazione, un object con durata di archiviazione automatica o dynamic ha un valore indeterminato. [ Nota: gli oggetti con durata di memorizzazione statica o thread sono inizializzati a zero, vedere 3.6.2. – nota finale ]

a ( sottolineatura mia ):

Se non è specificato alcun inizializzatore per un object, l’object viene inizializzato di default. Quando si ottiene la memorizzazione di un object con durata di memorizzazione automatica o dynamic, l’object ha un valore indeterminato e se non viene eseguita alcuna inizializzazione per l’object, quell’object conserva un valore indeterminato fino a quando tale valore non viene sostituito (5.17 [espr.ass]) . [Nota: gli oggetti con durata di memorizzazione statica o di thread sono inizializzati a zero, vedere 3.6.2 [basic.start.init]. -End note] Se un valore indeterminato viene prodotto da una valutazione, il comportamento non è definito tranne nei seguenti casi :

  • Se un valore indeterminato di tipo di carattere stretto senza segno (3.9.1 [basic.fundamental]) viene prodotto dalla valutazione di:

    • il secondo o terzo operando di un’espressione condizionale (5.16 [expr.cond]),

    • l’operando di destra di una virgola (5.18 [expr.comma]),

    • l’operando di un cast o conversione a un tipo di carattere stretto senza segno (4.7 [conv.integral], 5.2.3 [expr.type.conv], 5.2.9 [expr.static.cast], 5.4 [expr.cast]) , o

    • un’espressione di valore scartato (clausola 5 [expr]),

    quindi il risultato dell’operazione è un valore indeterminato.

  • Se un valore indeterminato di tipo di carattere stretto senza segno (3.9.1 [basic.fundamental]) viene prodotto dalla valutazione dell’operando di destra di un operatore di assegnazione semplice (5.17 [espr.ass]) il cui primo operando è un lvalue di unsigned narrow tipo di carattere, un valore indeterminato sostituisce il valore dell’object a cui fa riferimento l’operando di sinistra.

  • Se un valore indeterminato di tipo di carattere stretto senza segno (3.9.1 [basic.fundamental]) viene prodotto dalla valutazione dell’espressione di inizializzazione durante l’inizializzazione di un object di tipo di carattere stretto senza segno, tale object viene inizializzato su un valore indeterminato.

e incluso il seguente esempio:

[ Esempio:

 int f(bool b) { unsigned char c; unsigned char d = c; // OK, d has an indeterminate value int e = d; // undefined behavior return b ? d : 0; // undefined behavior if b is true } 

esempio finale ]

Possiamo trovare questo testo in N3936 che è l’attuale bozza di lavoro e N3937 è il C++14 DIS .

Prima di C ++ 1y

È interessante notare che prima di questa bozza diversamente da C che ha sempre avuto una nozione ben precisa di quali usi di valori indeterminati non erano definiti, C ++ usava il termine valore indeterminato senza nemmeno definirlo ( assumendo che non possiamo prendere a prestito la definizione da C99 ) e anche vedere il rapporto sui difetti 616 . Abbiamo dovuto fare affidamento sulla conversione lvalue-rvalue sottostimata, che nella bozza dello standard C ++ 11 è trattata nella sezione 4.1 Conversione da valore a valore nominale paragrafo 1 che dice:

[…] se l’object non è inizializzato, un programma che richiede questa conversione ha un comportamento non definito. […]


Note:

  1. 1787 è una revisione del rapporto sui difetti 616 , possiamo trovare quella informazione in N3903