63 votes

GOTO ou pas GOTO ?

Je travaille actuellement sur un projet où les instructions goto sont très utilisées. L'objectif principal des instructions goto est d'avoir une section de nettoyage dans une routine plutôt que de multiples déclarations de retour. Comme ci-dessous :

BOOL foo()
{
   BOOL bRetVal = FALSE;
   int *p = NULL;

   p = new int;
   if (p == NULL)
   {
     cout<<" OOM \n";
     goto Exit;
   }

   // Lot of code...

Exit:
   if(p)
   {
     delete p;
     p = NULL;
   }
   return bRetVal;
}

Cela rend les choses beaucoup plus faciles car nous pouvons suivre notre code de nettoyage à une section du code, c'est-à-dire après l'étiquette Exit.

Cependant, j'ai lu à de nombreux endroits que c'est une mauvaise pratique d'avoir des instructions goto.

Actuellement, je lis le _Code complet_ et il est dit que nous devons utiliser les variables à proximité de leurs déclarations. Si nous utilisons goto, nous devons déclarer/initialiser toutes les variables avant la première utilisation de goto, sinon le compilateur émettra des erreurs indiquant que l'initialisation de xx variables est ignorée par l'instruction goto.

Quel est le bon chemin ?


D'après le commentaire de Scott :

Il semble que l'utilisation de goto pour passer d'une section à l'autre soit mauvaise car elle rend le code difficile à lire et à comprendre.

Mais si nous utilisons goto uniquement pour aller en avant et vers une étiquette, alors cela devrait aller ( ?).

0 votes

Votre extrait de code n'a pas de retour et pas de gotos. Cela rend ton premier paragraphe un peu idiot.

0 votes

Le balisage faisait des choses bizarres - c'est corrigé maintenant.

0 votes

Le sujet donne l'impression d'une question argumentative. Mais je n'ai pas de bonnes oppositions

60voto

Tamas Czinege Points 49277

Je ne suis pas sûr de ce que vous entendez par nettoyer le code, mais en C++, il existe un concept appelé " l'acquisition des ressources est l'initialisation "et il devrait être de la responsabilité de vos destructeurs de nettoyer les choses.

(Notez qu'en C# et Java, ceci est généralement résolu par try/finally)

Pour plus d'informations, consultez cette page : http://www.research.att.com/~bs/bs_faq2.html#finalement

EDITAR : Laissez-moi clarifier un peu les choses.

Considérons le code suivant :

void MyMethod()
{
    MyClass *myInstance = new MyClass("myParameter");
    /* Your code here */
    delete myInstance;
}

Le problème : Que se passe-t-il si vous avez plusieurs sorties de la fonction ? Vous devez garder la trace de chaque sortie et supprimer vos objets à toutes les sorties possibles ! Sinon, vous aurez des fuites de mémoire et des ressources zombies, non ?

La solution : Utilisez plutôt des références d'objets, car elles sont nettoyées automatiquement lorsque le contrôle quitte la portée.

void MyMethod()
{
    MyClass myInstance("myParameter");
    /* Your code here */
    /* You don't need delete - myInstance will be destructed and deleted
     * automatically on function exit */
}

Oh oui, et utilisez std::unique_ptr ou quelque chose de similaire, car l'exemple ci-dessus, tel qu'il est, est évidemment imparfait.

0 votes

Cela permet de nettoyer le code et d'éviter les retours multiples de la routine qui sont parfois très difficiles à suivre.

6 votes

ALien01 : Les chemins de retour multiples et les multiples, "goto end of function" sont exactement égaux en difficulté à suivre.

0 votes

Le code ci-dessus est en C, donc les méthodes C++ ne semblent pas s'appliquer.

60voto

Gene Roberts Points 1059

Je n'ai jamais eu à utiliser un goto en C++. Jamais. JAMAIS. S'il y a une situation où il faut l'utiliser, c'est incroyablement rare. Si vous envisagez de faire de goto une partie standard de votre logique, quelque chose a dérapé.

2 votes

Les goto sont dans le langage pour une raison, certes, mais si vous envisagez de les utiliser, il y a 99,9% de chances que vous vous trompiez. N'écrivez pas votre code comme s'il tombait dans le cas des 0,01 %, car ce n'est probablement pas le cas.

42 votes

Parfois, vous avez besoin d'un goto pour sortir de boucles imbriquées.

18 votes

@rlbond : Bien que cette affirmation soit souvent répétée, il est tout aussi souvent prouvé qu'elle est fausse. (C'est Tagged C++ . Le C++ dispose de l'inlining. Vous pouvez donc toujours utiliser un return au lieu d'un goto .)

22voto

Brian Points 14040

Il y a essentiellement deux points que les gens soulèvent en ce qui concerne gotos et votre code :

  1. Goto est mauvais. Il est très rare de rencontrer un endroit où vous avez besoin de gotos, mais je ne suggérerais pas de le supprimer complètement. Bien que le C++ ait un flux de contrôle suffisamment intelligent pour rendre le goto rarement approprié.

  2. Votre mécanisme de nettoyage est faux : Ce point est bien plus important. En C, utiliser la gestion de la mémoire de façon autonome est non seulement acceptable, mais c'est souvent la meilleure façon de faire les choses. En C++, votre objectif devrait être d'éviter la gestion de la mémoire autant que possible. Vous devriez éviter la gestion de la mémoire autant que possible. Laissez le compilateur le faire pour vous. Plutôt que d'utiliser new il suffit de déclarer des variables. La seule fois où vous aurez vraiment besoin de gérer la mémoire est lorsque vous ne connaissez pas la taille de vos données à l'avance. Même dans ce cas, vous devriez essayer d'utiliser certaines des fonctions de gestion de la mémoire de l STL à la place.

Dans le cas où vous avez légitimement besoin de la gestion de la mémoire (vous n'avez pas vraiment fourni de preuve de cela), alors vous devriez encapsuler votre gestion de la mémoire dans une classe via des constructeurs pour allouer la mémoire et des déconstructeurs pour désallouer la mémoire.

Votre réponse selon laquelle votre façon de faire est beaucoup plus facile n'est pas vraiment vraie à long terme. Tout d'abord, une fois que vous vous serez familiarisé avec le C++, la création de tels constructeurs deviendra une seconde nature. Personnellement, je trouve qu'il est plus facile d'utiliser des constructeurs que d'utiliser du code de nettoyage, puisque je n'ai pas besoin de faire attention pour m'assurer que je désalloue correctement. Au lieu de cela, je peux simplement laisser l'objet quitter la portée et le langage s'en occupe pour moi. De plus, les maintenir est BEAUCOUP plus facile que de maintenir une section de nettoyage et beaucoup moins sujet à des problèmes.

En bref, goto peut être un bon choix dans certaines situations, mais pas dans celle-ci. Ici, c'est juste de la paresse à court terme.

20voto

Konrad Rudolph Points 231505

Votre code est extrêmement non-idiomatique et vous ne devriez jamais l'écrire. Vous émulez essentiellement C en C++. Mais d'autres l'ont fait remarquer et ont indiqué RAII comme l'alternative.

Cependant, votre code ne fonctionne pas comme vous vous y attendez, car ceci :

p = new int;
if(p==NULL) { … }

ne le fera pas jamais évaluer pour true (sauf si vous avez surchargé operator new d'une manière bizarre). Si operator new ne parvient pas à allouer suffisamment de mémoire, il lève une exception, il nunca , jamais renvoie à 0 du moins pas avec cet ensemble de paramètres ; il existe une surcharge spéciale de type placement-new qui prend une instance du type std::nothrow et qui renvoie en effet 0 au lieu de lancer une exception. Mais cette version est rarement utilisée dans le code normal. Certains codes de bas niveau ou des applications de dispositifs embarqués pourraient en bénéficier dans des contextes où le traitement des exceptions est trop coûteux.

Il en va de même pour votre delete bloc, comme Harald l'a dit : if (p) est inutile devant delete p .

De plus, je ne suis pas sûr que votre exemple ait été choisi intentionnellement car ce code peut être réécrit comme suit :

bool foo() // prefer native types to BOOL, if possible
{
    bool ret = false;
    int i;
    // Lots of code.
    return ret;
}

0 votes

Le nouvel opérateur retournera NULL. Consultez le lien : msdn.microsoft.com/fr/us/library/kftdy56f(VS.71).aspx

1 votes

Non, c'est ne le fera pas . Cet article utilise un autre new surcharge, à savoir l'opérateur nothrow new. C'est ce à quoi je faisais référence dans ma réponse ci-dessus. Je vais essayer de le clarifier davantage.

0 votes

En fait, le code émule Fortran, plutôt que C. Il n'y a aucune raison d'utiliser GOTO en C eiter.

17voto

Marc Charbonneau Points 30464

Probablement pas une bonne idée .

0 votes

Moi aussi. Je l'ai imprimé et affiché dans mon cube. Craignez le vélociraptor.

Prograide.com

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.

Powered by:

X