Co to "Won't x be leaked"znaczy? Typ xto wbudowany typ danych. Dlaczego nie wybierzesz lepszego przykładu?
Nawaz,
2
@Nawaz: Przykład jest doskonały. Niemal za każdym razem, gdy z kimś rozmawiam 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.
Wyścigi lekkości na orbicie,
1
@David: Zgadzam się, że to pytanie ma dużo więcej sensu, gdy zmienna ma nietrywialnego destruktora ... i szukałem odpowiedzi Tomalaka i znalazłem taki przykład. Ponadto, chociaż intjakiś nie może przeciekać, może przeciekać . Na przykład: void f(void) { new int(5); }przecieki int.
Ben Voigt,
Dlaczego nie zmienić pytania na coś w rodzaju: „Czy w podanym przykładzie ścieżka wykonania kodu zostanie przeniesiona z f () do main () bez czyszczenia stosu i innych funkcji powrotu z funkcji? Czy miałoby znaczenie, czy destruktor musiałby być nazywany? Czy jest taki sam w C? ” Czy to jedno i drugie podtrzymałoby intencję pytania, a jednocześnie pozwoliłoby uniknąć możliwych nieporozumień?
Jack V.
Odpowiedzi:
210
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).
1. Zakres etykiety
Nie możesz przeskakiwać między funkcjami:
voidf(){
int x = 0;
goto lol;
}
intmain(){
f();
lol:
return0;
}
// error: label 'lol' used but not defined
[n3290: 6.1/1]:[..] Zakres etykiety to funkcja, w której się pojawia. [..]
2. Inicjalizacja obiektu
Nie możesz przeskoczyć przez inicjalizację obiektu:
intmain(){
goto lol;
int x = 0;
lol:
return0;
}
// error: jump to label ‘lol’// error: from here// error: crosses initialization of ‘int x’
structT {
T() { cout << "*T"; }
~T() { cout << "~T"; }
};
intmain(){
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:
intmain(){
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:
intmain(){
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. [..]
[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. [..]
Wniosek
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.
Możesz zauważyć, że C nie zapobiega tym wszystkim niebezpiecznym rzeczom.
Daniel,
13
@Daniel: Pytanie i odpowiedź bardzo konkretnie dotyczą C ++, ale słuszna uwaga. Może moglibyśmy mieć kolejne FAQ, które rozwiałyby mit, że C i C ++ to to samo;)
Lightness Races in Orbit
3
@Tomalak: Nie sądzę, że się tutaj nie zgadzamy. Wiele odpowiedzi udzielonych na SO jest gdzieś wyraźnie udokumentowanych. Zwróciłem tylko uwagę, że programista C może kusić, aby zobaczyć tę odpowiedź i założyć, że jeśli działa w C ++, to powinno działać podobnie w C.
Daniel,
2
Możesz również chcieć dodać, że wszystkie te przeskakiwanie rzeczy inicjalizacji są takie same dla etykiet skrzynek.
PlasmaHH
12
Wow, właśnie założyłem, że semantyka C ++ została zepsuta dla goto, ale są zaskakująco rozsądne! Świetna odpowiedź.
"Won't x be leaked"
znaczy? Typx
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); }
przeciekiint
.Odpowiedzi:
Ostrzeżenie: ta odpowiedź dotyczy tylko języka C ++ ; zasady są zupełnie inne w C.
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ż, tolongjmp
może być na to podatny).Rozważ następujące mechanizmy, które zapobiegają robieniu „złych rzeczy” z etykietami (w tym
case
etykietami).1. Zakres etykiety
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
2. Inicjalizacja obiektu
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
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
3. Skakanie podlega zakresowi innych obiektów
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
Wniosek
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.źródło