J'écris un 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 rompre la boucle en mettant une rupture conditionnelle juste après le changement. Je veux juste savoir si C++ a déjà une construction pour cela.
Le code suivant doit être considéré comme une mauvaise forme, quelle que soit la langue ou la fonctionnalité souhaitée:
while( true ) {
}
La boucle while( true )
est de mauvaise forme car elle:
while(true)
pour des boucles qui ne sont pas infinies, nous perdons la capacité de communiquer de manière concise lorsque les boucles n'ont en réalité aucune condition de fin. (On peut soutenir que cela est déjà arrivé, alors le problème est sans objet.)Le code suivant est de meilleure forme:
while( isValidState() ) {
execute();
}
bool isValidState() {
return msg->state != DONE;
}
Pas de drapeau. Non goto
. Pas exception. Facile à changer. Facile à lire. Facile à réparer. De plus le code:
Le deuxième point est important. Sans savoir comment le code fonctionne, si quelqu'un me demandait de faire en sorte que la boucle principale laisse un peu de temps processeur aux autres threads (ou processus), deux solutions s'imposent:
Facilement insérer la pause:
while( isValidState() ) {
execute();
sleep();
}
Remplacer exécuter:
void execute() {
super->execute();
sleep();
}
Ce code est plus simple (donc plus facile à lire) qu’une boucle avec une switch
incorporée. La méthode isValidState
doit uniquement déterminer si la boucle doit continuer. Le cheval de travail de la méthode doit être résumé dans la méthode execute
, qui permet aux sous-classes de remplacer le comportement par défaut (tâche difficile utilisant les variables incorporées switch
et goto
).
Comparez la réponse suivante (à une question Python) postée sur StackOverflow:
while True:
choice = raw_input('What do you want? ')
if choice == 'restart':
continue
else:
break
print 'Break!'
Contre:
choice = 'restart';
while choice == 'restart':
choice = raw_input('What do you want? ')
print 'Break!'
Ici, while True
génère 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
, c'est-à-dire:
for (;;) {
switch(msg->state) {
case MSGTYPE
// code
continue; // continue with loop
case DONE:
break;
}
break;
}
Utilisez l'instruction continue
pour terminer chaque étiquette de casse dans laquelle vous souhaitez que la boucle continue et utilisez l'instruction break
pour terminer les étiquettes de casse devant 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 façon astucieuse de le faire serait de le mettre dans une fonction:
int yourfunc() {
while(true) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
return;
}
}
}
Facultatif (mais «mauvaises pratiques»): comme déjà suggéré, vous pouvez utiliser un goto ou envoyer une exception à l'intérieur du commutateur.
Autant que je sache, il n'y a pas de "double rupture" ou de construction similaire en C++. Le plus proche serait un goto
- qui, bien qu'il ait une mauvaise connotation dans son nom, existe dans le langage pour une raison - tant qu'il est utilisé avec précaution et avec parcimonie, c'est une option viable.
Vous pouvez placer votre commutateur dans une fonction séparée comme celle-ci:
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 aller à goto, n'utilisez pas d'exception pour sortir d'une boucle. L'exemple suivant montre à quel point cela pourrait être moche:
try {
while ( ... ) {
switch( ... ) {
case ...:
throw 777; // I'm afraid of goto
}
}
}
catch ( int )
{
}
J'utiliserais goto
comme dans this answer. 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 ici à 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 suivantes:
while ( msg->state != DONE ) {
switch( msg->state ) {
case MSGTYPE: // ...
break;
// ... more stuff ...
}
Dans ce cas, il n'y a pas de construction C++ pour sortir de la boucle.
Utilisez un indicateur pour interrompre la boucle ou, le cas échéant, extrayez votre code dans une fonction et utilisez return
.
Vous pouvez potentiellement utiliser goto, mais je préférerais définir un indicateur qui arrête la boucle. Puis sortez de l'interrupteur.
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. Alternativement, un do..while () avec un drapeau de sortie pourrait suffire.
do {
switch(option){
case 1: ..; break;
...
case n: .. ;break;
default: flag = false; break;
}
} while(flag);
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;
Je suis étonné de voir à quel point cela 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!
La façon la plus simple de le faire est de mettre un simple IF avant de faire le SWITCH, et que le SI teste votre condition pour sortir de la boucle .......... aussi simple que possible.
Le mot clé break
en C++ termine uniquement l'itération ou l'instruction switch
la plus imbriquée. Ainsi, vous ne pouvez 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 avez besoin de faire quelque chose lorsque msg->state
est égal à DONE
(comme 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();
}
Puis utilisez plutôt:
for (; msg->state != DONE; msg = next_message()) {
switch (msg->state) {
case MSGTYPE:
//...
break;
//...
}
}
assert(msg->state == DONE);
do_cleanup();
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;
}