Que veut "Won't x be leaked"dire? Le type de xest un type de données intégré. Pourquoi ne choisissez-vous pas un meilleur exemple?
Nawaz
2
@Nawaz: L'exemple est parfait tel qu'il est. Presque chaque fois que j'en parle à quelqu'un goto, ils pensent que même les variables automatiques de durée de stockage sont en quelque sorte «fuites». Que vous et moi savons le contraire est tout à fait autre chose.
Courses de légèreté en orbite le
1
@David: Je suis d'accord que cette question a beaucoup plus de sens lorsque la variable a un destructeur non trivial ... et j'ai regardé dans la réponse de Tomalak et ai trouvé un tel exemple. De plus, même si un intne peut pas fuir, il peut fuir . Par exemple: void f(void) { new int(5); }fuit un fichier int.
Ben Voigt
Pourquoi ne pas changer la question en quelque chose comme "Dans l'exemple donné, le chemin d'exécution du code sera-t-il transféré de f () à main () sans effacer la pile et les autres fonctionnalités de retour de fonction? Est-ce important si un destructeur devait être appelé? Est-ce la même chose en C? " Cela maintiendrait-il l'intention de la question, tout en évitant les éventuelles idées fausses?
Jack V.
Réponses:
210
Avertissement: cette réponse concerne uniquement C ++ ; les règles sont assez différentes en C.
Ne xsera- t-il pas divulgué?
Non, absolument pas.
C'est un mythe qui gotoest une construction de bas niveau qui vous permet de remplacer les mécanismes de portée intégrés de C ++. (Si quelque chose, c'est longjmppeut-être sujet à cela.)
Considérez les mécanismes suivants qui vous empêchent de faire de «mauvaises choses» avec les étiquettes (qui incluent les caseétiquettes).
1. Portée de l'étiquette
Vous ne pouvez pas sauter entre les fonctions:
void f(){int x =0;goto lol;}int main(){
f();
lol:return0;}// error: label 'lol' used but not defined
[n3290: 6.1/1]:[..] La portée d'une étiquette est la fonction dans laquelle elle apparaît. [..]
2. Initialisation d'objet
Vous ne pouvez pas sauter à travers l'initialisation d'objet:
int main(){goto lol;int x =0;
lol:return0;}// error: jump to label ‘lol’// error: from here// error: crosses initialization of ‘int x’
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]:[..] Le transfert hors d'une boucle, hors d'un bloc ou en arrière au-delà d'une variable initialisée avec une durée de stockage automatique implique la destruction d'objets avec une durée de stockage automatique qui sont dans la portée au point transféré mais pas au point transféré vers . [..]
Vous ne pouvez pas sauter dans la portée d'un objet, même s'il n'est pas explicitement initialisé:
int main(){goto lol;{
std::string x;
lol:
x ="";}}// error: jump to label ‘lol’// error: from here// error: crosses initialization of ‘std::string x’
... sauf pour certains types d'objets , que le langage peut gérer indépendamment car ils ne nécessitent pas de construction "complexe":
int main(){goto lol;{int x;
lol:
x =0;}}// OK
[n3290: 6.7/3]:Il est possible de transférer dans un bloc, mais pas d'une manière qui contourne les déclarations avec l'initialisation. Un programme qui saute d'un point où une variable avec une durée de stockage automatique n'est pas dans la portée à un point où elle est dans la portée est mal formé sauf si la variable a un type scalaire, un type de classe avec un constructeur par défaut trivial et un destructeur trivial, un cv-qualifié de l'un de ces types, ou un tableau de l'un des types précédents et est déclaré sans initialiseur. [..]
struct T {
T(){ cout <<"*T";}~T(){ cout <<"~T";}};int main(){{
T t;goto lol;}
lol:return0;}// *T~T
[n3290: 6.6/2]:A la sortie d'un périmètre (quelle qu'en soit la réalisation), les objets à durée de stockage automatique (3.7.3) qui ont été construits dans ce périmètre sont détruits dans l'ordre inverse de leur construction. [..]
Conclusion
Les mécanismes ci-dessus garantissent que gotocela ne vous permet pas de casser la langue.
Bien sûr, cela ne signifie pas automatiquement que vous « devrait » utiliser gotopour un problème donné, mais il ne signifie pas qu'il est loin d'être aussi « mal » , comme les fils de mythe commun les gens à croire.
Vous remarquerez peut-être que C n'empêche pas toutes ces choses dangereuses de se produire.
Daniel
13
@Daniel: La question et la réponse concernent très spécifiquement le C ++, mais c'est juste. Peut-être que nous pouvons avoir une autre FAQ dissipant le mythe selon lequel C et C ++ sont les mêmes;)
Lightness Races in Orbit
3
@Tomalak: Je ne pense pas que nous soyons en désaccord ici. Bon nombre des réponses données sur SO sont explicitement documentées quelque part. Je faisais juste valoir qu'il pourrait être tentant pour un programmeur C de voir cette réponse et de supposer que si cela fonctionne en C ++, cela devrait fonctionner de la même manière en C.
Daniel
2
Vous voudrez peut-être également ajouter que tous ces sauts par-dessus l'initialisation sont les mêmes pour les étiquettes de cas.
PlasmaHH
12
Wow, je venais de supposer que la sémantique de C ++ était cassée pour goto, mais elles sont étonnamment saines! Très bonne réponse.
"Won't x be leaked"
dire? Le type dex
est un type de données intégré. Pourquoi ne choisissez-vous pas un meilleur exemple?goto
, ils pensent que même les variables automatiques de durée de stockage sont en quelque sorte «fuites». Que vous et moi savons le contraire est tout à fait autre chose.int
ne peut pas fuir, il peut fuir . Par exemple:void f(void) { new int(5); }
fuit un fichierint
.Réponses:
Avertissement: cette réponse concerne uniquement C ++ ; les règles sont assez différentes en C.
Non, absolument pas.
C'est un mythe qui
goto
est une construction de bas niveau qui vous permet de remplacer les mécanismes de portée intégrés de C ++. (Si quelque chose, c'estlongjmp
peut-être sujet à cela.)Considérez les mécanismes suivants qui vous empêchent de faire de «mauvaises choses» avec les étiquettes (qui incluent les
case
étiquettes).1. Portée de l'étiquette
Vous ne pouvez pas sauter entre les fonctions:
2. Initialisation d'objet
Vous ne pouvez pas sauter à travers l'initialisation d'objet:
Si vous revenez à l'initialisation de l'objet, alors "l'instance" précédente de l'objet est détruite :
Vous ne pouvez pas sauter dans la portée d'un objet, même s'il n'est pas explicitement initialisé:
... sauf pour certains types d'objets , que le langage peut gérer indépendamment car ils ne nécessitent pas de construction "complexe":
3. Le saut respecte la portée des autres objets
De même, les objets avec une durée de stockage automatique ne sont pas «divulgués» lorsque vous
goto
sortez de leur portée :Conclusion
Les mécanismes ci-dessus garantissent que
goto
cela ne vous permet pas de casser la langue.Bien sûr, cela ne signifie pas automatiquement que vous « devrait » utiliser
goto
pour un problème donné, mais il ne signifie pas qu'il est loin d'être aussi « mal » , comme les fils de mythe commun les gens à croire.la source