Czy to prawda, że gotoprzeskakuje 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 xwycieknie?
Czy to prawda, że gotoprzeskakuje 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 xwycieknie?
"Won't x be leaked"znaczy? Typ xto 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.
intjakiś 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
xwycieknie?
Nie, absolutnie nie.
To mit, który gotojest konstrukcją niskiego poziomu, która pozwala przesłonić wbudowane mechanizmy określania zakresu C ++. (Jeśli już, to longjmpmoże być na to podatny).
Rozważ następujące mechanizmy, które zapobiegają robieniu „złych rzeczy” z etykietami (w tym caseetykietami).
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 gotoz 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 gotodla danego problemu, ale to nie znaczy, że nie jest aż tak „zło” jako wspólny odprowadzeniach mit ludzi do wiary.