Czy to prawda, że goto
przeskakuje przez fragmenty kodu bez wywoływania destruktorów i innych rzeczy?
na przykład
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
Nie x
wycieknie?
Czy to prawda, że goto
przeskakuje przez fragmenty kodu bez wywoływania destruktorów i innych rzeczy?
na przykład
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
Nie x
wycieknie?
"Won't x be leaked"
znaczy? Typ x
to wbudowany typ danych. Dlaczego nie wybierzesz lepszego przykładu?
goto
, myślą, że nawet zmienne automatycznego czasu przechowywania są w jakiś sposób „wyciekające”. To, że ty i ja wiemy, że jest inaczej, nie ma znaczenia.
int
jakiś nie może przeciekać, może przeciekać . Na przykład: void f(void) { new int(5); }
przecieki int
.
Odpowiedzi:
Ostrzeżenie: ta odpowiedź dotyczy tylko języka C ++ ; zasady są zupełnie inne w C.
Nie
x
wycieknie?
Nie, absolutnie nie.
To mit, który goto
jest konstrukcją niskiego poziomu, która pozwala przesłonić wbudowane mechanizmy określania zakresu C ++. (Jeśli już, to longjmp
może być na to podatny).
Rozważ następujące mechanizmy, które zapobiegają robieniu „złych rzeczy” z etykietami (w tym case
etykietami).
Nie możesz przeskakiwać między funkcjami:
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
// error: label 'lol' used but not defined
[n3290: 6.1/1]:
[..] Zakres etykiety to funkcja, w której się pojawia. [..]
Nie możesz przeskoczyć przez inicjalizację obiektu:
int main() {
goto lol;
int x = 0;
lol:
return 0;
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘int x’
Jeśli przeskoczysz z powrotem przez inicjalizację obiektu, poprzednia „instancja” obiektu zostanie zniszczona :
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]:
[..] Przeniesienie z pętli, z bloku lub z powrotem poza zainicjowaną zmienną z automatycznym czasem przechowywania obejmuje zniszczenie obiektów z automatycznym czasem przechowywania, które są w zakresie w punkcie przeniesionym z, ale nie w punkcie przeniesionym do . [..]
Nie możesz wskoczyć w zakres obiektu, nawet jeśli nie jest on jawnie zainicjowany:
int main() {
goto lol;
{
std::string x;
lol:
x = "";
}
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘std::string x’
... z wyjątkiem pewnych rodzajów obiektów , z którymi język może sobie poradzić niezależnie, ponieważ nie wymagają one „skomplikowanej” konstrukcji:
int main() {
goto lol;
{
int x;
lol:
x = 0;
}
}
// OK
[n3290: 6.7/3]:
Możliwe jest przeniesienie do bloku, ale nie w sposób omijający deklaracje przy inicjalizacji. Program, który przeskakuje z punktu, w którym zmienna z automatycznym czasem przechowywania nie znajduje się w zakresie, do punktu, w którym jest w zakresie, jest źle sformułowana, chyba że zmienna ma typ skalarny, typ klasy z trywialnym konstruktorem domyślnym i trywialnym destruktorem, a cv kwalifikowana wersja jednego z tych typów lub tablica jednego z powyższych typów i jest zadeklarowana bez inicjatora. [..]
Podobnie, obiekty z automatycznym czas przechowywania są nie „wyciekły”, gdy goto
z ich zakresem :
struct T {
T() { cout << "*T"; }
~T() { cout << "~T"; }
};
int main() {
{
T t;
goto lol;
}
lol:
return 0;
}
// *T~T
[n3290: 6.6/2]:
Po wyjściu z zakresu (jakkolwiek zrealizowane) obiekty z automatycznym czasem przechowywania (3.7.3), które zostały zbudowane w tym zakresie, są niszczone w odwrotnej kolejności do ich budowy. [..]
Zapewniają to powyższe mechanizmy goto
nie pozwoli ci to złamać języka.
Oczywiście, nie oznacza automatycznie, że „powinien” stosowanie goto
dla danego problemu, ale to nie znaczy, że nie jest aż tak „zło” jako wspólny odprowadzeniach mit ludzi do wiary.