Achtung: Diese Antwort bezieht sich auf C ++ nur ; Die Regeln sind in C ganz anders.
Wird nicht x
durchgesickert sein?
Nein auf keinen Fall.
Es ist ein Mythos, bei dem goto
es sich um ein Konstrukt auf niedriger Ebene handelt, mit dem Sie die in C ++ integrierten Scoping-Mechanismen überschreiben können. (Wenn überhaupt, ist dies longjmp
möglicherweise anfällig dafür.)
Berücksichtigen Sie die folgenden Mechanismen, die verhindern, dass Sie mit Etiketten (einschließlich case
Etiketten) "schlechte Dinge" tun .
1. Beschriftungsbereich
Sie können nicht über Funktionen springen:
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
// error: label 'lol' used but not defined
[n3290: 6.1/1]:
[..] Der Umfang eines Etiketts ist die Funktion, in der es erscheint. [..]
2. Objektinitialisierung
Sie können nicht über die Objektinitialisierung springen:
int main() {
goto lol;
int x = 0;
lol:
return 0;
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘int x’
Wenn Sie über die Objektinitialisierung zurückspringen , wird die vorherige "Instanz" des Objekts zerstört :
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]:
[..] Die Übertragung aus einer Schleife, aus einem Block oder zurück an einer initialisierten Variablen mit automatischer Speicherdauer vorbei beinhaltet die Zerstörung von Objekten mit automatischer Speicherdauer, die an dem Punkt, der von übertragen wurde, aber nicht an dem Punkt, an den übertragen wurde, in den Geltungsbereich fallen . [..]
Sie können nicht in den Bereich eines Objekts springen, auch wenn es nicht explizit initialisiert wurde:
int main() {
goto lol;
{
std::string x;
lol:
x = "";
}
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘std::string x’
... mit Ausnahme bestimmter Arten von Objekten , mit denen die Sprache unabhängig umgehen kann, da sie keine "komplexe" Konstruktion erfordern:
int main() {
goto lol;
{
int x;
lol:
x = 0;
}
}
// OK
[n3290: 6.7/3]:
Es ist möglich, in einen Block zu übertragen, jedoch nicht so, dass Deklarationen bei der Initialisierung umgangen werden. Ein Programm, das von einem Punkt, an dem sich eine Variable mit automatischer Speicherdauer nicht im Gültigkeitsbereich befindet, zu einem Punkt springt, an dem sie sich im Gültigkeitsbereich befindet, ist fehlerhaft, es sei denn, die Variable hat einen Skalartyp, einen Klassentyp mit einem trivialen Standardkonstruktor und einen trivialen Destruktor, a cv-qualifizierte Version eines dieser Typen oder ein Array eines der vorhergehenden Typen und wird ohne Initialisierer deklariert. [..]
3. Das Springen hält sich an den Umfang anderer Objekte
Ebenso Objekte mit automatischer Speicherdauer sind nicht „durchgesickert“ , wenn Sie goto
aus ihrem Umfang :
struct T {
T() { cout << "*T"; }
~T() { cout << "~T"; }
};
int main() {
{
T t;
goto lol;
}
lol:
return 0;
}
// *T~T
[n3290: 6.6/2]:
Beim Verlassen eines Bereichs (wie auch immer ausgeführt) werden Objekte mit automatischer Speicherdauer (3.7.3), die in diesem Bereich erstellt wurden, in umgekehrter Reihenfolge ihrer Erstellung zerstört. [..]
Fazit
Die oben genannten Mechanismen stellen sicher, dass goto
Sie die Sprache nicht brechen können.
Natürlich bedeutet dies nicht automatisch, dass Sie es goto
für ein bestimmtes Problem "verwenden" sollten , aber es bedeutet , dass es bei weitem nicht so "böse" ist, wie der verbreitete Mythos die Menschen glauben macht.