Ich schreibe Code, der so aussieht:
while(true) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
break; // **HERE, I want to break out of the loop itself**
}
}
Gibt es einen direkten Weg, das zu tun?
Ich weiß, dass ich ein Flag verwenden kann, und aus der Schleife ausbrechen kann, indem Sie unmittelbar nach der Umschaltung eine bedingte Pause setzen. Ich möchte nur wissen, ob C++ bereits ein Konstrukt dafür hat.
Der folgende Code sollte ungeachtet der Sprache oder der gewünschten Funktionalität als fehlerhaft betrachtet werden:
while( true ) {
}
Die while( true )
-Schleife hat eine schlechte Form, weil sie:
while(true)
für Schleifen verwendet, die nicht unendlich sind, können wir nicht mehr direkt kommunizieren, wenn Schleifen tatsächlich keine Beendigungsbedingung haben. (Das ist wohl schon passiert, also ist der Punkt irrelevant.)Der folgende Code hat eine bessere Form:
while( isValidState() ) {
execute();
}
bool isValidState() {
return msg->state != DONE;
}
Keine Fahne Nein goto
. Keine Ausnahmen. Einfach zu ändern Leicht zu lesen. Einfach zu reparieren Zusätzlich der Code:
Der zweite Punkt ist wichtig. Ohne zu wissen, wie der Code funktioniert, wenn mir jemand fragt, ob die Hauptschleife anderen Threads (oder Prozessen) etwas CPU-Zeit hätte, fallen zwei Lösungen ein:
Fügen Sie einfach die Pause ein:
while( isValidState() ) {
execute();
sleep();
}
Überschreiben ausführen:
void execute() {
super->execute();
sleep();
}
Dieser Code ist einfacher (also leichter lesbar) als eine Schleife mit einer eingebetteten switch
. Die isValidState
-Methode sollte nur bestimmen, ob die Schleife fortgesetzt werden soll. Das Arbeitspferd der Methode sollte in die execute
-Methode abstrahiert werden, wodurch Unterklassen das Standardverhalten überschreiben können (eine schwierige Aufgabe, die eine eingebettete switch
und goto
verwendet).
Vergleichen Sie die folgende Antwort (zu einer Python-Frage), die in StackOverflow gepostet wurde:
while True:
choice = raw_input('What do you want? ')
if choice == 'restart':
continue
else:
break
print 'Break!'
Gegen:
choice = 'restart';
while choice == 'restart':
choice = raw_input('What do you want? ')
print 'Break!'
Hier führt while True
zu irreführendem und zu komplexem Code.
Sie können goto
verwenden.
while ( ... ) {
switch( ... ) {
case ...:
goto exit_loop;
}
}
exit_loop: ;
Eine alternative Lösung ist die Verwendung des Schlüsselworts continue
in Kombination mit break
, d. H .:
for (;;) {
switch(msg->state) {
case MSGTYPE
// code
continue; // continue with loop
case DONE:
break;
}
break;
}
Verwenden Sie die continue
-Anweisung, um jede Fallbezeichnung zu beenden, an der die Schleife fortgesetzt werden soll, und verwenden Sie die break
-Anweisung, um die Fallbezeichnungen zu beenden, die die Schleife beenden sollen.
Natürlich funktioniert diese Lösung nur, wenn nach der switch-Anweisung kein zusätzlicher Code ausgeführt werden muss.
Eine nette Methode, dies zu tun, wäre, dies in eine Funktion einzufügen:
int yourfunc() {
while(true) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
return;
}
}
}
Optional (aber "schlechte Praktiken"): Wie bereits vorgeschlagen, können Sie einen goto verwenden oder eine Ausnahme innerhalb des Switch auslösen.
AFAIK gibt es in C++ keinen "double break" oder ein ähnliches Konstrukt. Am nächsten wäre ein goto
- der zwar einen schlechten Bezug zu seinem Namen hat, jedoch aus einem bestimmten Grund in der Sprache vorhanden ist - solange er vorsichtig und sparsam verwendet wird, ist dies eine gangbare Option.
Sie können Ihren Switch in eine separate Funktion wie folgt setzen:
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())
;
Auch wenn Sie "goto" nicht mögen, verwenden Sie keine Ausnahme, um eine Schleife zu beenden. Das folgende Beispiel zeigt, wie hässlich es sein kann:
try {
while ( ... ) {
switch( ... ) {
case ...:
throw 777; // I'm afraid of goto
}
}
}
catch ( int )
{
}
Ich würde goto
wie in this answer verwenden. In diesem Fall macht goto
den Code klarer als jede andere Option. Ich hoffe, dass diese Frage hilfreich sein wird.
Ich denke jedoch, dass die Verwendung von goto
hier die einzige Option ist, da der String while(true)
verwendet wird. Sie sollten das Refactoring Ihrer Schleife in Betracht ziehen. Ich würde die folgende Lösung annehmen:
bool end_loop = false;
while ( !end_loop ) {
switch( msg->state ) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
end_loop = true; break;
}
}
Oder sogar das Folgende:
while ( msg->state != DONE ) {
switch( msg->state ) {
case MSGTYPE: // ...
break;
// ... more stuff ...
}
In diesem Fall gibt es kein C++ - Konstrukt, um die Schleife zu durchbrechen.
Verwenden Sie entweder ein Flag, um die Schleife zu unterbrechen, oder extrahieren Sie (falls zutreffend) Ihren Code in eine Funktion, und verwenden Sie return
.
Sie könnten möglicherweise goto verwenden, aber ich würde es vorziehen, ein Flag zu setzen, das die Schleife stoppt. Dann brechen Sie den Schalter aus.
Nein, C++ hat dafür kein Konstrukt, da das Schlüsselwort "break" bereits für das Verlassen des Switch-Blocks reserviert ist. Alternativ könnte ein do..while () mit einem Exit-Flag ausreichen.
do {
switch(option){
case 1: ..; break;
...
case n: .. ;break;
default: flag = false; break;
}
} while(flag);
Warum nicht einfach die Bedingung in Ihrer while-Schleife beheben, wodurch das Problem behoben wird?
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**
}
}
Meiner Ansicht nach;
while(msg->state != mExit)
{
switch(msg->state)
{
case MSGTYPE: // ...
break;
case DONE:
// ..
// ..
msg->state =mExit;
break;
}
}
if (msg->state ==mExit)
msg->state =DONE;
Es überrascht mich, wie einfach dies ist, wenn man die Tiefe der Erklärungen bedenkt.
bool imLoopin = true;
while(imLoopin) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
imLoopin = false;
break;
}
}
LOL !! Ja wirklich! Das ist alles was du brauchst! Eine zusätzliche Variable!
Der einfachste Weg, dies zu tun, besteht darin, vor dem SWITCH eine einfache IF zu setzen, und diese IF testet Ihre Bedingung, um die Schleife zu beenden. So einfach wie möglich
Das Schlüsselwort break
in C++ beendet nur die am stärksten verschachtelte umgebende Iteration oder die Anweisung switch
. Daher konnten Sie die while (true)
-Schleife nicht direkt in der switch
-Anweisung durchbrechen. Sie könnten jedoch den folgenden Code verwenden, der meiner Meinung nach ein hervorragendes Muster für diese Art von Problem ist:
for (; msg->state != DONE; msg = next_message()) {
switch (msg->state) {
case MSGTYPE:
//...
break;
//...
}
}
Wenn Sie etwas tun müssen, wenn msg->state
gleich DONE
ist (beispielsweise eine Bereinigungsroutine ausführen), platzieren Sie diesen Code unmittelbar nach der for
-Schleife. wenn Sie derzeit haben:
while (true) {
switch (msg->state) {
case MSGTYPE:
//...
break;
//...
case DONE:
do_cleanup();
break;
}
if (msg->state == DONE)
break;
msg = next_message();
}
Dann verwenden Sie stattdessen:
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**
}
}
Ich habe dasselbe Problem und wurde mit einer Flagge gelöst.
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;
}