Frage

Ich schreibe einige Code, der wie folgt 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 eine direkte Möglichkeit, das zu tun?

Ich weiß, dass ich einen Flag verwenden kann, und von der Schleife bricht durch eine bedingte Pause unmittelbar nach dem Schalter setzen. Ich will nur wissen, ob C ++ einige Konstrukte für diesen bereits.

War es hilfreich?

Lösung

Premise

Der folgende Code sollte schlechte Form in Betracht gezogen werden, unabhängig von der Sprache oder gewünschte Funktionalität:

while( true ) {
}

Unterstützung Argumente

Die while( true ) Schleife ist schlechter Stil, weil es:

  • Bricht den impliziten Vertrag mit einer while-Schleife.
    • Die while-Schleife Erklärung sollte ausdrücklich angeben, die nur Ausgangsbedingung.
  • bedeutet, dass es für immer Schleifen.
    • -Code innerhalb der Schleife muss der Abschluss Klausel zu verstehen, zu lesen.
    • Loops, die den Benutzer von einer Beendigung des Programms aus dem Programm für immer verhindern wiederholen.
  • ist ineffizient.
    • Es gibt mehrere Schleifenabschlussbedingungen, einschließlich der Prüfung auf "true".
  • ist anfällig für Fehler.
    • Kann nicht leicht festzustellen, wo Code zu setzen, die für jede Iteration immer ausgeführt werden.
  • führt unnötig komplexen Code zu.
  • Automatische Quellcodeanalyse.
    • Um Fehler, Programmkomplexitätsanalyse, Sicherheitsüberprüfungen oder automatisch anderes Quellcode Verhalten ohne Codeausführung ableiten, die anfängliche Bruchbedingung spezifiziert (s) ermöglicht Algorithmen nützlich Invarianten, um zu bestimmen, wodurch die automatische Quellcodeanalyse Metriken zu verbessern.
  • Endlosschleifen.
    • Wenn jeder immer while(true) for-Schleifen verwendet, die nicht unendlich sind, verlieren wir die Fähigkeit zu kommunizieren prägnant, wenn Schleifen tatsächlich keine Abbruchbedingung haben. (Argumentieren, ist dies bereits geschehen ist, so dass der Punkt ist strittig.)

Alternative zu "Go To"

Der folgende Code ist besser Form:

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

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

Vorteile

Keine Flagge. Kein goto. Keine Ausnahmen. Einfach zu ändern. Leicht zu lesen. Einfach zu beheben. Zusätzlich wird der Code:

  1. Trennt das Wissen über die Arbeitsbelastung der Schleife von der Schleife selbst.
  2. Erlaubt jemand den Code beibehalten wird auf einfache Weise die Funktionalität zu erweitern.
  3. Erlaubt mehr Abschlussbedingungen an einem Ort zugeordnet werden.
  4. Trennt den Abschluss Klausel aus dem Code auszuführen.
  5. Ist sicherer für Kernkraftwerke. ; -)

Der zweite Punkt ist wichtig. Ohne zu wissen, wie der Code funktioniert, wenn jemand mich gebeten, die Hauptschleife machen lassen andere Threads (oder Prozesse) haben einige CPU-Zeit, zwei Lösungen in den Sinn kommen:

Option # 1

Problemlos legen Sie die Pause:

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

Option # 2

Überschreiben ausführen:

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

Dieser Code ist einfacher (und damit leichter zu lesen) als eine Schleife mit einer eingebetteten switch. Die isValidState Methode sollte nur festzustellen, ob die Schleife fortgesetzt werden sollte. Das Zugpferd des Verfahrens sollte in das execute Verfahren abstrahiert werden, die Subklassen das Standardverhalten (eine schwierige Aufgabe, unter Verwendung eines eingebetteten switch und goto).

außer Kraft setzen können

Python-Beispiel

Vergleichen Sie die folgende Antwort (auf eine Python Frage), die auf Stackoverflow gepostet:

  1. Schleife für immer.
  2. Stellen Sie den Benutzer zur Eingabe ihrer Wahl.
  3. Wenn Eingabe des Benutzers ist 'Neustart', weiter Looping für immer.
  4. Andernfalls stoppen Looping für immer.
  5. Ende.
Code
while True: 
    choice = raw_input('What do you want? ')

    if choice == 'restart':
        continue
    else:
        break

print 'Break!' 

Versus:

  1. Initialisieren des Benutzers Wahl.
  2. Schleife, während die Auswahl des Benutzers ist das Wort ‚Neustart‘.
  3. Stellen Sie den Benutzer zur Eingabe ihrer Wahl.
  4. Ende.
Code
choice = 'restart';

while choice == 'restart': 
    choice = raw_input('What do you want? ')

print 'Break!'

Hier while True Ergebnisse in irreführend und übermäßig komplexen Code.

Andere Tipps

Sie können goto verwenden.

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

   }
}
exit_loop: ;

Eine alternative Lösung ist das Stichwort continue in Kombination mit break zu verwenden, das heißt:.

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

Mit der continue Anweisung jeden Fall Etikett zu beenden, wo Sie die Schleife wollen die break Anweisung fortzusetzen und verwenden zu Fall Etikett zu beenden, die die Schleife beendet werden sollen.

Natürlich ist diese Lösung funktioniert nur, wenn kein zusätzlicher Code ist nach der switch-Anweisung auszuführen.

Ein neatish Weg, dies zu tun, wäre dies in eine Funktion zu setzen:

int yourfunc() {

    while(true) {

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

    }
}

Optional (aber ‚schlechte Praxis‘): Wie bereits vorgeschlagen, dass Sie eine goto verwenden könnten, oder eine Ausnahme innerhalb des Schalters werfen

.

AFAIK gibt es keine „doppelte Pause“ oder ähnliches Konstrukt in C ++ ist. Die nächstgelegene ein goto wäre -, die zwar eine schlechte Konnotation zu seinem Namen hat, gibt es in der Sprache aus einem Grund -. Solange sie sorgfältig verwendet wird und sparsam, es ist eine praktikable Option

Sie können Ihren Schalter in eine separate Funktion so:

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())
    ;

Es gibt keine C ++ Konstrukt für in diesem Fall aus der Schleife zu brechen.

Entweder einen Flag verwenden, um die Schleife oder (falls geeignet) extrahiert Code in eine Funktion und Verwendung return zu unterbrechen.

Sie könnten möglicherweise goto verwenden, aber ich würde es vorziehen, einen Flag zu setzen, die die Schleife beendet. Dann bricht aus dem Schalter.

Warum nicht einfach den Zustand in Ihrer while-Schleife beheben, so dass das Problem verschwinden?

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**
    }
}

Nein, C ++ nicht über ein Konstrukt dafür gegeben, dass das Schlüsselwort „break“ ist bereits reserviert zum Verlassen des Schalterblockes. Alternativ kann ein do..while () mit einem Verlassensflag könnte ausreichen.

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

Ich denke;

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

Der einfachste Weg, es zu tun ist, ein einfach zu setzen, wenn, bevor Sie den SWITCH tun, und dass, wenn Ihr Zustand testen, für die Schleife verlass .......... so einfach, wie es kann

Das break Schlüsselwort in C ++ beendet nur die meist verschachtelt umschließenden Iteration oder switch Anweisung. So konnte man nicht aus der while (true) Schleife bricht direkt innerhalb der switch Anweisung; jedoch können Sie den folgenden Code verwenden, was meiner Meinung nach ein ausgezeichnetes 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 (wie eine Bereinigungsroutine ausgeführt wird), legen Sie dann diesen Code unmittelbar nach der for Schleife; das heißt, wenn Sie Zeit 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();

Es erstaunt mich, wie einfach das ist die Tiefe der Erklärungen unter Berücksichtigung ... Hier ist alles, was Sie brauchen ...

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 Sie brauchen! Eine zusätzliche Variable!

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 gleiches Problem und löste einen Flag verwendet.

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;
}

Wenn ich C ++ Syntax gut erinnern, können Sie ein Label hinzufügen Aussagen break, genau wie für goto. Also, was Sie leicht geschrieben werden würde wollen:

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
  }
}
scroll top