Avvertenza: questa risposta riguarda solo C ++ ; le regole sono abbastanza diverse in C.
Non x
sarà trapelato?
No, assolutamente no.
È un mito che goto
è un costrutto di basso livello che consente di sovrascrivere i meccanismi di scoping incorporati di C ++. (Se non altro, longjmp
potrebbe essere incline a questo.)
Considera i seguenti meccanismi che ti impediscono di fare "cose cattive" con le etichette (che includono le case
etichette).
1. Ambito dell'etichetta
Non puoi saltare tra le funzioni:
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
// error: label 'lol' used but not defined
[n3290: 6.1/1]:
[..] Lo scopo di un'etichetta è la funzione in cui appare. [..]
2. Inizializzazione dell'oggetto
Non puoi saltare attraverso l'inizializzazione degli oggetti:
int main() {
goto lol;
int x = 0;
lol:
return 0;
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘int x’
Se torni indietro attraverso l'inizializzazione dell'oggetto, la precedente "istanza" dell'oggetto viene distrutta :
struct T {
T() { cout << "*T"; }
~T() { cout << "~T"; }
};
int main() {
int x = 0;
lol:
T t;
if (x++ < 5)
goto lol;
}
// Output: *T~T*T~T*T~T*T~T*T~T*T~T
[n3290: 6.6/2]:
[..] Il trasferimento fuori da un loop, da un blocco o indietro oltre una variabile inizializzata con durata di memorizzazione automatica comporta la distruzione di oggetti con durata di memorizzazione automatica che sono nell'ambito nel punto trasferito da ma non nel punto trasferito a . [..]
Non puoi saltare nell'ambito di un oggetto, anche se non è inizializzato esplicitamente:
int main() {
goto lol;
{
std::string x;
lol:
x = "";
}
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘std::string x’
... ad eccezione di alcuni tipi di oggetti , che il linguaggio può gestire indipendentemente perché non richiedono una costruzione "complessa":
int main() {
goto lol;
{
int x;
lol:
x = 0;
}
}
// OK
[n3290: 6.7/3]:
È possibile trasferire in un blocco, ma non in un modo che aggiri le dichiarazioni con inizializzazione. Un programma che salta da un punto in cui una variabile con durata di memorizzazione automatica non è nell'ambito di applicazione a un punto in cui è nell'ambito è mal formato a meno che la variabile non abbia un tipo scalare, un tipo di classe con un banale costruttore predefinito e un banale distruttore, un cv-qualificato versione di uno di questi tipi o un array di uno dei tipi precedenti e viene dichiarato senza un inizializzatore. [..]
3. Il salto si attiene all'ambito di altri oggetti
Allo stesso modo, gli oggetti con durata di archiviazione automatica non vengono "trapelati" quando esci dal loro ambitogoto
:
struct T {
T() { cout << "*T"; }
~T() { cout << "~T"; }
};
int main() {
{
T t;
goto lol;
}
lol:
return 0;
}
// *T~T
[n3290: 6.6/2]:
All'uscita da un ambito (comunque realizzato), gli oggetti con durata di memorizzazione automatica (3.7.3) che sono stati costruiti in tale ambito vengono distrutti nell'ordine inverso rispetto alla loro costruzione. [..]
Conclusione
I meccanismi di cui sopra garantiscono che goto
non ti permetta di rompere la lingua.
Naturalmente, questo non significa automaticamente che si "dovrebbe" uso goto
per un dato problema, ma lo fa significa che non è quasi come "male", come i comuni derivazioni mito le persone a credere.