Exemples de bons gotos en C ou c++ [fermé]

dans ce thread, nous regardons des exemples de bonnes utilisations de goto en C ou C++. Il est inspiré par une réponse que les gens ont voté parce qu'ils pensaient que je plaisantais.

résumé (étiquette changée de l'original pour rendre l'intention encore plus claire):

infinite_loop:

    // code goes here

goto infinite_loop;

Pourquoi c'est mieux que les alternatives:

  • c'est spécifique. goto est le la construction linguistique qui cause un branche inconditionnelle. Alternative dépend de l'utilisation des structures soutenir les branches conditionnelles, avec un dégénéré toujours vrai condition.
  • l'étiquette documente l'intention Sans commentaires supplémentaires.
  • Le lecteur n'a pas à scanner le code d'intervention pour le début de break s (bien qu'il soit encore possible pour un hacker sans principes pour simuler continue avec un early goto ).

Règles:

  • prétendre que les gotophobes n'ont pas gagner. Il est entendu que ce qui précède ne peut pas être utilisé en code réel parce que il va à l'encontre établi idiome.
  • Supposons que nous avons tous entendu parler de 'Goto considéré comme nocif" et de savoir que goto peut être utilisé pour écrire code spaghetti.
  • si vous n'êtes pas d'accord avec un exemple, critique sur le mérite technique seul ("Parce que les gens n'aiment pas goto " n'est pas un raison technique).

voyons si nous pouvons en parler comme des adultes.

Modifier

cette question semble terminée maintenant. Il a généré des réponses de haute qualité. Merci à tout le monde, surtout ceux qui ont pris mon petit exemple de boucle au sérieux. La plupart des sceptiques étaient inquiets en l'absence de bloc de portée. @Quinmars souligné dans un commentaire, vous pouvez toujours mettre des accolades autour de la corps de boucle. Je note en passant que for(;;) et while(true) ne vous donnent pas les bretelles gratuitement soit (et les omettre peut causer des bogues fâcheux). De toute façon, je ne vais pas perdre plus de de votre cerveau sur cette bagatelle - je peux vivre avec l'inoffensif et idiomatique for(;;) et while(true) (aussi bien si je veux garder mon travail).

en considérant les autres réponses, je vois que beaucoup de gens considèrent goto comme quelque chose que vous toujours réécrire dans un autre façon. Bien sûr, vous pouvez éviter un goto en introduisant une boucle, un drapeau supplémentaire, une pile de if imbriquée, ou autre, mais pourquoi ne pas considérer si goto est peut-être le meilleur outil pour le travail? Autrement dit, quelle laideur les gens sont-ils prêts à endurer pour éviter d'utiliser une fonctionnalité de langage intégrée dans le but visé? De mon point de vue est que même l'ajout d'un indicateur est un prix trop élevé à payer. J'aime mes variables à représenter les choses dans les domaines de problèmes ou de solutions. "Seulement pour éviter un goto ' ne suffit pas.

j'accepte la première réponse qui a donné le modèle C pour la ramification à un bloc de nettoyage. IMO, Cela fait le cas le plus fort pour un goto de toutes les réponses postées, certainement si vous le mesurez par les contorsions qu'un ennemi doit traverser pour l'éviter.

79
demandé sur Community 2008-10-29 06:58:30

16 réponses

est un truc que j'ai entendu dire. Je ne l'ai jamais vu à l'état sauvage. Et ça ne s'applique qu'à C parce que C++ a RAII pour faire ça plus idiomatiquement.

void foo()
{
    if (!doA())
        goto exit;
    if (!doB())
        goto cleanupA;
    if (!doC())
        goto cleanupB;

    /* everything has succeeded */
    return;

cleanupB:
    undoB();
cleanupA:
    undoA();
exit:
    return;
}
87
répondu Greg Rogers 2014-02-11 04:00:48

Le classique de la nécessité de GOTO en C est comme suit:

for ...
  for ...
    if(breakout_condition) 
      goto final;

final:

il n'y a pas de façon simple de sortir des boucles imbriquées sans goto.

85
répondu Paul Nathan 2008-10-29 04:31:43

Voici mon exemple non-idiot, (de Stevens APITUE) pour les appels système Unix qui peuvent être interrompus par un signal.

restart:
    if (system_call() == -1) {
        if (errno == EINTR) goto restart;

        // handle real errors
    }

l'alternative est une boucle dégénérée. Cette version se lit comme l'anglais "si l'appel système a été interrompu par un signal, redémarrer".

32
répondu fizzer 2011-04-23 10:57:51

si L'appareil de Duff n'a pas besoin de goto, vous non plus! ;)

void dsend(int count) {
    int n;
    if (!count) return;
    n = (count + 7) / 8;
    switch (count % 8) {
      case 0: do { puts("case 0");
      case 7:      puts("case 7");
      case 6:      puts("case 6");
      case 5:      puts("case 5");
      case 4:      puts("case 4");
      case 3:      puts("case 3");
      case 2:      puts("case 2");
      case 1:      puts("case 1");
                 } while (--n > 0);
    }
}

code ci-dessus de Wikipedia entry .

14
répondu Mitch Wheat 2008-10-29 04:08:23

Knuth a écrit un papier "programmation structurée avec des déclarations GOTO", vous pouvez l'obtenir par exemple de ici . Vous trouverez de nombreux exemples.

14
répondu zvrba 2008-10-29 07:17:10

très courant.

do_stuff(thingy) {
    lock(thingy);

    foo;
    if (foo failed) {
        status = -EFOO;
        goto OUT;
    }

    bar;
    if (bar failed) {
        status = -EBAR;
        goto OUT;
    }

    do_stuff_to(thingy);

OUT:
    unlock(thingy);
    return status;
}

le seul cas que j'utilise goto est pour sauter en avant, généralement hors des blocs, et jamais dans les blocs. Cela évite l'abus de do{}while(0) et d'Autres constructions qui augmentent l'imbrication, tout en maintenant le code structuré et lisible.

12
répondu ephemient 2008-10-29 04:18:02

Je n'ai rien contre gotos en général, mais je peux penser à plusieurs raisons pour lesquelles vous ne voudriez pas les utiliser pour une boucle comme vous avez mentionné:

  • il ne limite pas la portée donc toutes les variables temp que vous utilisez à l'intérieur ne seront pas libérées avant plus tard.
  • il ne limite pas la portée donc il pourrait y avoir des bugs.
  • il ne limite pas la portée donc vous ne pouvez pas réutiliser les mêmes noms de variables plus tard dans le code futur dans le même portée.
  • il ne limite pas la portée donc vous avez la possibilité de sauter sur une déclaration variable.
  • les gens n'y sont pas habitués et cela rendra votre code plus difficile à lire.
  • boucles imbriquées de ce type peuvent conduire au code spaghetti, boucles normales ne conduiront pas au code spaghetti.
12
répondu Brian R. Bondy 2011-04-23 10:57:28

Un bon endroit pour utiliser un goto est une procédure qui peut interrompre à plusieurs points, dont chacun nécessite différents niveaux de nettoyage. Les Gotophobes peuvent toujours remplacer les gotos par du code structuré et une série de tests, mais je pense que c'est plus simple parce qu'il élimine l'indentation excessive:

if (!openDataFile())
  goto quit;

if (!getDataFromFile())
  goto closeFileAndQuit;

if (!allocateSomeResources)
  goto freeResourcesAndQuit;

// Do more work here....

freeResourcesAndQuit:
   // free resources
closeFileAndQuit:
   // close file
quit:
   // quit!
7
répondu Adam Liss 2008-10-29 04:09:17

@fizzer.myopenid.com: votre extrait de code posté est équivalent à ce qui suit:

    while (system_call() == -1)
    {
        if (errno != EINTR)
        {
            // handle real errors

            break;
        }
    }

je préfère certainement ce formulaire.

7
répondu Mitch Wheat 2008-10-29 04:35:48

même si j'ai appris à détester ce modèle au fil du temps, il est ancré dans la programmation COM.

#define IfFailGo(x) {hr = (x); if (FAILED(hr)) goto Error}
...
HRESULT SomeMethod(IFoo* pFoo) {
  HRESULT hr = S_OK;
  IfFailGo( pFoo->PerformAction() );
  IfFailGo( pFoo->SomeOtherAction() );
Error:
  return hr;
}
6
répondu JaredPar 2008-10-29 06:49:36

voici un exemple de bon goto:

// No Code
5
répondu FlySwat 2008-10-29 04:01:13

j'ai vu goto correctement utilisé mais les situations sont normalement laides. C'est seulement lors de l'utilisation de goto lui-même est beaucoup moins pire que l'original. @Johnathon Holland le problème c'est que votre version est moins claire. les gens semblent avoir peur des variables locales:

void foo()
{
    bool doAsuccess = doA();
    bool doBsuccess = doAsuccess && doB();
    bool doCsuccess = doBsuccess && doC();

    if (!doCsuccess)
    {
        if (doBsuccess)
            undoB();
        if (doAsuccess)
            undoA();
    }
}

et je préfère les boucles comme celle-ci mais certaines personnes préfèrent while(true) .

for (;;)
{
    //code goes here
}
1
répondu Charles Beattie 2011-01-05 19:29:57

ma plainte à ce sujet est que vous perdez la détermination de la portée du bloc; toutes les variables locales déclarées entre les gotos restent en vigueur si la boucle est jamais rompue. (Peut-être que vous supposez que la boucle tourne pour toujours; Je ne pense pas que ce soit ce que l'auteur de la question originale demandait, cependant.)

le problème de cadrage est plus un problème avec C++, car certains objets peuvent dépendre de leur dtor étant appelé à des moments appropriés.

Pour moi, le meilleur la raison d'utiliser goto est au cours d'un processus d'initialisation en plusieurs étapes où il est essentiel que toutes les entrées soient désactivées en cas d'échec, a la:

if(!foo_init())
  goto bye;

if(!bar_init())
  goto foo_bye;

if(!xyzzy_init())
  goto bar_bye;

return TRUE;

bar_bye:
 bar_terminate();

foo_bye:
  foo_terminate();

bye:
  return FALSE;
0
répondu Jim Nelson 2008-10-29 04:11:44

Je n'utilise pas goto moi-même, mais j'ai travaillé avec une personne qui les utiliserait dans des cas spécifiques. Si je me souviens bien, sa raison d'être portait sur les questions de rendement - il avait aussi des règles spécifiques pour comment . Toujours dans la même fonction, et l'étiquette était toujours en dessous de la déclaration goto.

0
répondu user25306 2008-10-29 05:53:48
#include <stdio.h>
#include <string.h>

int main()
{
    char name[64];
    char url[80]; /*The final url name with http://www..com*/
    char *pName;
    int x;

    pName = name;

    INPUT:
    printf("\nWrite the name of a web page (Without www, http, .com) ");
    gets(name);

    for(x=0;x<=(strlen(name));x++)
        if(*(pName+0) == '"151900920"' || *(pName+x) == ' ')
        {
            printf("Name blank or with spaces!");
            getch();
            system("cls");
            goto INPUT;
        }

    strcpy(url,"http://www.");
    strcat(url,name);
    strcat(url,".com");

    printf("%s",url);
    return(0);
}
0
répondu StrifeSephiroth 2014-01-10 12:59:14

@Greg:

Pourquoi ne pas faire votre exemple comme ceci:

void foo()
{
    if (doA())
    {    
        if (doB())
        {
          if (!doC())
          {
             UndoA();
             UndoB();
          }
        }
        else
        {
          UndoA();
        }
    }
    return;
}
-1
répondu FlySwat 2008-10-29 04:37:36