Comment sortir d’une boucle depuis l’intérieur d’un switch?

J’écris du code qui ressemble à ceci:

while(true) { switch(msg->state) { case MSGTYPE: // ... break; // ... more stuff ... case DONE: break; // **HERE, I want to break out of the loop itself** } } 

Y a-t-il un moyen direct de le faire?

Je sais que je peux utiliser un drapeau et quitter la boucle en mettant une pause conditionnelle juste après le changement. Je veux juste savoir si C ++ a déjà une construction pour cela.

Prémisse

Le code suivant doit être considéré comme une forme incorrecte, indépendamment de la langue ou de la fonctionnalité souhaitée:

 while( true ) { } 

Arguments de soutien

La boucle while( true ) est de mauvaise forme car elle:

  • Brise le contrat implicite d’une boucle while.
    • La déclaration de boucle while doit indiquer explicitement la seule condition de sortie.
  • Implique qu’il boucle pour toujours.
    • Le code dans la boucle doit être lu pour comprendre la clause de terminaison.
    • Les boucles qui se répètent empêchent toujours l’utilisateur de terminer le programme depuis le programme.
  • Est inefficace.
    • Il existe plusieurs conditions de terminaison de boucle, y compris la vérification de “true”.
  • Est sujette aux bogues.
    • Impossible de déterminer facilement où placer le code qui sera toujours exécuté pour chaque itération.
  • Donne un code inutilement complexe.

Alternative à “Go To”

Le code suivant est mieux formé:

 while( isValidState() ) { execute(); } bool isValidState() { return msg->state != DONE; } 

Avantages

Pas de drapeau Pas de goto . Pas exception. Facile à changer Facile à lire. Facile à réparer De plus le code:

  1. Isole la connaissance de la charge de travail de la boucle de la boucle elle-même.
  2. Permet à quelqu’un de maintenir le code d’étendre facilement la fonctionnalité.
  3. Permet d’atsortingbuer plusieurs conditions de terminaison au même endroit.
  4. Séparer la clause de fin du code à exécuter.
  5. Est plus sûr pour les centrales nucléaires. 😉

Le deuxième point est important. Sans savoir comment le code fonctionne, si quelqu’un m’a demandé de faire la boucle principale, laissez les autres threads (ou processus) gagner du temps CPU, deux solutions me viennent à l’esprit:

Option 1

Insérez la pause facilement:

 while( isValidState() ) { execute(); sleep(); } 

Option 2

Remplacer exécuter:

 void execute() { super->execute(); sleep(); } 

Ce code est plus simple (donc plus facile à lire) qu’une boucle avec un switch incorporé. La méthode isValidState doit uniquement déterminer si la boucle doit continuer. Le workhorse de la méthode doit être résumé dans la méthode execute , ce qui permet aux sous-classes de remplacer le comportement par défaut (une tâche difficile en utilisant un switch et un goto incorporés).

Exemple Python

Comparez la réponse suivante (à une question Python) qui a été publiée sur StackOverflow:

  1. Boucle pour toujours
  2. Demandez à l’utilisateur d’entrer son choix.
  3. Si la saisie de l’utilisateur est “restart”, continuez à boucler pour toujours.
  4. Sinon, arrêtez de boucler pour toujours.
  5. Fin.

Code

 while True: choice = raw_input('What do you want? ') if choice == 'restart': continue else: break print 'Break!' 

Contre:

  1. Initialiser le choix de l’utilisateur.
  2. Boucle alors que le choix de l’utilisateur est le mot “redémarrer”.
  3. Demandez à l’utilisateur d’entrer son choix.
  4. Fin.

Code

 choice = 'restart'; while choice == 'restart': choice = raw_input('What do you want? ') print 'Break!' 

Ici, while True traduit par un code trompeur et trop complexe.

Vous pouvez utiliser goto .

 while ( ... ) { switch( ... ) { case ...: goto exit_loop; } } exit_loop: ; 

Une autre solution consiste à utiliser le mot-clé continue en combinaison avec break , à savoir:

 for (;;) { switch(msg->state) { case MSGTYPE // code continue; // continue with loop case DONE: break; } break; } 

Utilisez l’instruction continue pour terminer chaque étiquette de cas où vous souhaitez que la boucle continue et utilisez l’instruction break pour terminer les étiquettes de cas qui doivent terminer la boucle.

Bien entendu, cette solution ne fonctionne que s’il n’ya pas de code supplémentaire à exécuter après l’instruction switch.

Une manière intéressante de le faire serait de mettre cela dans une fonction:

 int yourfunc() { while(true) { switch(msg->state) { case MSGTYPE: // ... break; // ... more stuff ... case DONE: return; } } } 

Facultativement (mais «mauvaises pratiques»): comme déjà suggéré, vous pouvez utiliser un goto ou lancer une exception dans le commutateur.

AFAIK il n’y a pas de “double break” ou de construction similaire en C ++. Le plus proche serait un goto – qui, bien qu’il ait une mauvaise connotation à son nom, existe dans la langue pour une raison – dans la mesure où il est utilisé avec prudence et parcimonie, c’est une option viable.

Vous pouvez mettre votre commutateur dans une fonction distincte comme ceci:

 bool myswitchfunction() { switch(msg->state) { case MSGTYPE: // ... break; // ... more stuff ... case DONE: return false; // **HERE, I want to break out of the loop itself** } return true; } while(myswitchfunction()) ; 

Même si vous n’aimez pas goto, n’utilisez pas une exception pour quitter une boucle. L’exemple suivant montre à quel point il peut être moche:

 try { while ( ... ) { switch( ... ) { case ...: throw 777; // I'm afraid of goto } } } catch ( int ) { } 

Je voudrais utiliser goto comme dans cette réponse. Dans ce cas, goto rendra le code plus clair que toute autre option. J’espère que cette question sera utile.

Mais je pense que l’utilisation de goto est la seule option à cause de la chaîne while(true) . Vous devriez envisager de refactoriser votre boucle. Je suppose que la solution suivante:

 bool end_loop = false; while ( !end_loop ) { switch( msg->state ) { case MSGTYPE: // ... break; // ... more stuff ... case DONE: end_loop = true; break; } } 

Ou même les suivants:

 while ( msg->state != DONE ) { switch( msg->state ) { case MSGTYPE: // ... break; // ... more stuff ... } 

Il n’y a pas de construction C ++ pour sortir de la boucle dans ce cas.

Utilisez un indicateur pour interrompre la boucle ou (le cas échéant) extrayez votre code dans une fonction et utilisez return .

Vous pourriez potentiellement utiliser goto, mais je préférerais définir un drapeau qui arrête la boucle. Ensuite, sortez de l’interrupteur.

Pourquoi ne pas simplement corriger la condition dans votre boucle while, provoquant la disparition du problème?

 while(msg->state != DONE) { switch(msg->state) { case MSGTYPE: // ... break; // ... more stuff ... case DONE: // We can't get here, but for completeness we list it. break; // **HERE, I want to break out of the loop itself** } } 

Je pense;

 while(msg->state != mExit) { switch(msg->state) { case MSGTYPE: // ... break; case DONE: // .. // .. msg->state =mExit; break; } } if (msg->state ==mExit) msg->state =DONE; 

Non, C ++ n’a pas de construction pour cela, étant donné que le mot clé “break” est déjà réservé pour quitter le bloc de commutation. Sinon, un do..while () avec un indicateur de sortie pourrait suffire.

 do { switch(option){ case 1: ..; break; ... case n: .. ;break; default: flag = false; break; } } while(flag); 

La manière la plus simple de le faire est de mettre un simple IF avant de faire le SWITCH, et que le IF teste votre condition pour sortir de la boucle ………. aussi simple que cela puisse être

Le mot-clé break en C ++ termine uniquement l’itération ou l’instruction switch la plus nestede. Ainsi, vous ne pouviez pas sortir de la boucle while (true) directement dans l’instruction switch ; Cependant, vous pouvez utiliser le code suivant, ce qui, à mon avis, est un excellent modèle pour ce type de problème:

 for (; msg->state != DONE; msg = next_message()) { switch (msg->state) { case MSGTYPE: //... break; //... } } 

Si vous deviez faire quelque chose lorsque msg->state égal à DONE (par exemple, exécuter une routine de nettoyage), placez ce code immédiatement après la boucle for ; c’est à dire si vous avez actuellement:

 while (true) { switch (msg->state) { case MSGTYPE: //... break; //... case DONE: do_cleanup(); break; } if (msg->state == DONE) break; msg = next_message(); } 

Ensuite, utilisez plutôt:

 for (; msg->state != DONE; msg = next_message()) { switch (msg->state) { case MSGTYPE: //... break; //... } } assert(msg->state == DONE); do_cleanup(); 

Cela m’étonne à quel point c’est simple compte tenu de la profondeur des explications … Voici tout ce dont vous avez besoin …

 bool imLoopin = true; while(imLoopin) { switch(msg->state) { case MSGTYPE: // ... break; // ... more stuff ... case DONE: imLoopin = false; break; } } 

LOL !! Vraiment! C’est tout ce dont vous avez besoin! Une variable supplémentaire!

 while(MyCondition) { switch(msg->state) { case MSGTYPE: // ... break; // ... more stuff ... case DONE: MyCondition=false; // just add this code and you will be out of loop. break; // **HERE, you want to break out of the loop itself** } } 

J’ai eu le même problème et résolu en utilisant un drapeau.

 bool flag = false; while(true) { switch(msg->state) { case MSGTYPE: // ... break; // ... more stuff ... case DONE: flag = true; // **HERE, I want to break out of the loop itself** } if(flag) break; } 

Si je me souviens bien de la syntaxe C ++, vous pouvez append une étiquette pour break instructions, comme pour goto . Donc, ce que vous voulez serait facilement écrit:

 while(true) { switch(msg->state) { case MSGTYPE: // ... break; // ... more stuff ... case DONE: break outofloop; // **HERE, I want to break out of the loop itself** } } outofloop: // rest of your code here 
  while(true) { switch(x) { case 1: { break; } break; case 2: //some code here break; default: //some code here } }