Saltare su un'inizializzazione variabile non è corretto o causa un comportamento indefinito?


17

Considera questo codice:

void foo()
{
    goto bar;
    int x = 0;
    bar: ;
}

GCC e Clang lo rifiutano , perché il salto per bar:bypassare l'inizializzazione variabile. MSVC non si lamenta affatto (tranne l'uso di xafter bar:provoca un avviso).

Possiamo fare una cosa simile con un switch:

void foo()
{
    switch (0)
    {
        int x = 0;
        case 0: ;
    }
}

Ora tutti e tre i compilatori emettono errori .

Quei frammenti sono mal formati? O causano UB?

Pensavo che entrambi fossero mal formati, ma non riesco a trovare le parti rivelatrici dello standard. [stmt.goto] non dice nulla al riguardo, e nemmeno [stmt.select] .


1
Il problema sarebbe più banale se lo usi xdopo il salto.
Jarod42,

1
non lo standard, ma qui è possibile trovare alcune informazioni al riguardo: en.cppreference.com/w/cpp/language/goto in particolare: "Se il trasferimento del controllo entra nello scopo di qualsiasi variabile automatica (ad es. saltando in avanti su una dichiarazione dichiarazione), il programma è mal formato (non può essere compilato), a meno che ... "
idclev 463035818

Aggiungi il /permissive-flag a MSVC e si lamenterà anche. Non so se il comportamento di MSVC senza quella bandiera sia ben definito (lo presumo, altrimenti perché lo permetterebbero?).
noce

@walnut "altrimenti perché lo permetterebbero" Forse per compatibilità all'indietro, o perché non si preoccupano troppo dello standard. Tutti i compilatori principali non sono conformi allo standard nelle impostazioni predefinite.
HolyBlackCat

Risposte:


20

È mal formato quando l'inizializzazione non è vacua.

[Stmt.dcl]

3 È possibile trasferire in un blocco, ma non in un modo che ignori le dichiarazioni con l'inizializzazione (comprese quelle in condizioni e istruzioni init). Un programma che salta da un punto in cui una variabile con durata di memorizzazione automatica non rientra nel campo di applicazione a un punto in cui si trova nel campo di applicazione è mal formato a meno che la variabile non abbia un'inizializzazione vacua ([basic.life]). In tal caso, le variabili con inizializzazione vuota sono costruite nell'ordine della loro dichiarazione.

L'inizializzatore rende l'inizializzazione non vacua. Al contrario, questo

void foo()
{
    goto bar;
    int x; // no initializer
    bar: ;
}

sarebbe ben formato. Sebbene xsi applichino le solite avvertenze sull'uso con un valore indeterminato.


le dichiarazioni variabili non devono comunque essere la prima cosa in un ambito?
Cruncher,

4
@Cruncher - C89 lo ha richiesto. Il C ++ non lo ha mai fatto, e nemmeno il C moderno.
StoryTeller - Unslander Monica

3

Da goto :

Se il trasferimento del controllo entra nell'ambito di qualsiasi variabile automatica (ad es. Saltando in avanti su una dichiarazione di dichiarazione), il programma è mal formato (non può essere compilato), a meno che tutte le variabili il cui ambito è inserito abbiano

  1. tipi scalari dichiarati senza inizializzatori
  2. tipi di classe con banali costruttori predefiniti e banali distruttori dichiarati senza inizializzatori
  3. versioni qualificate per cv di una delle precedenti
  4. array di uno dei precedenti
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.