Est-il vrai que goto
saute d'un bout à l'autre du code sans appeler les destructeurs et autres ?
par exemple
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
Ne le fera pas x
être divulguée ?
Est-il vrai que goto
saute d'un bout à l'autre du code sans appeler les destructeurs et autres ?
par exemple
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
Ne le fera pas x
être divulguée ?
<strong>Avertissement : </strong>Cette réponse concerne C++ <em>seulement </em>; les règles sont très différentes en C.
Ne le fera pas
x
être divulguée ?
Non, absolument pas.
C'est un mythe que goto
est une construction de bas niveau qui permet d'outrepasser les mécanismes de cadrage intégrés au C++. (S'il y a quelque chose, c'est longjmp
qui peuvent être sujettes à ce phénomène).
Considérez les mécanismes suivants qui vous empêchent de faire de "mauvaises choses" avec les étiquettes (ce qui inclut case
étiquettes).
Il n'est pas possible de passer d'une fonction à l'autre :
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
// 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. dans laquelle elle apparaît. [..]
Il n'est pas possible de passer outre l'initialisation d'un objet :
int main() {
goto lol;
int x = 0;
lol:
return 0;
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘int x’
Si vous sautez retour lors de l'initialisation de l'objet, alors l'instance précédente de l'objet est détruite :
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]:
[ ] Transférer hors d'une boucle, hors d'un bloc, ou revenir en arrière d'une variable initialisée avec une durée de stockage automatique implique la destruction d'objets ayant une durée de stockage automatique qui sont dans portée au moment du transfert, mais pas au moment du transfert. vers. [..]
Vous ne pouvez pas entrer dans le champ d'application 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’
... à l'exception de certains types d'objets que le langage peut traiter sans problème parce qu'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 d'effectuer un transfert dans un bloc, mais pas d'une manière qui permette de contourner la loi. mais pas d'une manière qui contourne les déclarations avec l'initialisation. Un programme qui saute d'un point où une variable à durée de stockage automatique n'est pas dans la portée à un point où elle est dans la portée est mal formé à moins que la variable est de type scalaire, de type classe avec un constructeur par défaut trivial et une et un destructeur trivial, une version qualifiée cv d'un de ces types, ou un de ces types, ou un tableau de l'un des types précédents et est déclarée sans initialisateur. [..]
De même, les objets à durée de stockage automatique son no "fuit" lorsque vous goto
hors de leur champ d'application :
struct T {
T() { cout << "*T"; }
~T() { cout << "~T"; }
};
int main() {
{
T t;
goto lol;
}
lol:
return 0;
}
// *T~T
[n3290: 6.6/2]:
Lors de la sortie d'un champ d'application (quelle que soit la manière dont il a été réalisé), les objets avec une durée de stockage automatique (3.7.3) qui ont été construits dans cette portée sont détruits dans l'ordre inverse de leur construction. [..]
Les mécanismes susmentionnés garantissent que goto
ne vous permet pas d'enfreindre la langue.
Bien entendu, cela ne signifie pas automatiquement que vous "devriez" utiliser goto
pour un problème donné, mais il fait Cela signifie qu'elle est loin d'être aussi "maléfique" que le mythe commun le laisse entendre.
@Ben : Ne le fait pas [n3290: 18.10/4]:
"La signature de la fonction longjmp(jmp_buf jbuf, int val)
a un comportement plus restreint dans cette norme internationale. A setjmp
/ longjmp
a un comportement indéfini si l'on remplace la paire d'appels setjmp
y longjmp
par catch et throw invoquerait tout destructeur non trivial pour tout objet automatique." casser cela ?
@Daniel : La question et la réponse concernent très spécifiquement le C++, mais c'est juste. Peut-être pourrions-nous avoir une autre FAQ qui dissiperait le mythe selon lequel C et C++ sont identiques ;)
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
0 votes
En rapport : stackoverflow.com/questions/1258201/ (mais je voulais le faire à partir de zéro, proprement !)
15 votes
Qu'est-ce que
"Won't x be leaked"
signifie ? Le type dex
est un type de données intégré. Pourquoi ne pas choisir un meilleur exemple ?2 votes
@Nawaz : L'exemple est parfait tel qu'il est. Presque chaque fois que je parle à quelqu'un de
goto
Ils pensent que même les variables de durée de stockage automatique font l'objet d'une "fuite". Le fait que vous et moi sachions le contraire n'a rien à voir avec la question.1 votes
@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 j'ai trouvé un tel exemple. De plus, alors qu'un
int
ne peut pas fuir, il peut faire l'objet d'une fuite . Par exemple :void f(void) { new int(5); }
fuites etint
.0 votes
Pourquoi ne pas modifier la question en quelque chose comme "Dans l'exemple donné, le chemin d'exécution du code passera-t-il de f() à main() sans effacer la pile et sans autre fonctionnalité de retour de fonction ? Cela aurait-il une importance si un destructeur devait être appelé ? Est-ce la même chose en C ?" Est-ce que cela permettrait à la fois de conserver l'intention de la question et d'éviter les idées fausses ?
0 votes
@Jack : Oui, je suis d'accord avec cela (bien que la langue puisse avoir un niveau de connaissance élevé).