2010-08-09 4 views
9

Sto preparando un certo codice:C++: rompere il ciclo principale

for(int a = 1; a <= 100; a++) //loop a (main loop) 
{ 
    for(int b = 1000; b <= 2000; b++) //loop b 
    { 
     if(b == 1555) 
      break; 
    } 

    for(int c = 2001; c <= 3000; c++) //loop c 
    { 
     . 
     . 
     . 
    } 
} 

voglio rompere il ciclo principale (variabile del ciclo int a) utilizzando un'istruzione break; nel b ciclo (variabile di ciclo int b).

Come posso farlo?

+3

Se sono stato informato correttamente, alcune lingue sostengono il costrutto 'rompere N' dove' n' è il numero di cicli annidati di uscire da. Ho ragione? –

+0

@And http: // download-LLNW.oracle.com/javase/tutorial/java/nutsandbolts/branch.html – Anycorn

+1

@Andreas: questo non è uno di questi. @sundowatch: rifatta il tuo codice, non solo risolverà il tuo problema, ma il tuo codice è più pulito e più gestibile. – GManNickG

risposta

20

vi consiglio il refactoring il codice in una funzione. Poi si può solo return da quella funzione invece di utilizzare break:

void myFunc() 
{ 
    for(int a = 1; a <= 100; a++) //loop a (main loop) 
    { 
     for(int b = 1000; b <= 2000; b++) //loop b 
     { 
      if(b == 1555) // Logic is just an example, 
       return; // since it will always return 
     } 

     . 
     . 
     . 
    } 
} 

questo - o forse anche un refactoring più coinvolto del vostro codice - dovrebbe prestarsi a una soluzione pulita ed elegante. In alternativa, se si desidera solo una soluzione rapida è possibile utilizzare una variabile di condizione:

for(int a = 1; a <= 100; a++) //loop a (main loop) 
{ 
    bool cond = false; 

    for(int b = 1000; b <= 2000; b++) //loop b 
    { 
     if(b == 1555){ 
      cond = true; 
      break; 
     } 
    } 

    if (cond) break; 

    . 
    . 
    . 
} 

Altri hanno suggerito di usare goto. Anche se questa è un'altra soluzione rapida, la raccomando vivamente contro, specialmente se si lavora in un ambiente rigoroso in cui il codice verrà sottoposto a peer review e utilizzato per anni lungo la strada.

In mio parere l'approccio goto è un po 'più difficile da mantenere di un refactoring funzione/ritorno, soprattutto in seguito quando qualcuno apporta modifiche al codice. Inoltre dovrai giustificare lo goto a tutti gli altri membri del team che capita di imbattersi nel codice.

+9

Questo funziona per due livelli, ma non si adatta bene oltre. Questo è il caso in cui digiti i denti e usi 'goto'. –

+14

@James: Oppure rifatta il tuo brutto codice multi-livello e non fare né l'uno né l'altro. – GManNickG

+3

@GMan: concordato. La mia soluzione tipica sarebbe quella di mettere il corpo del loop esterno in una subroutine, e usare "return". –

34

Utilizzare un goto.

for(int a = 1; a <= 100; a++) //loop a (main loop) 
{ 
    for(int b = 1000; b <= 2000; b++) //loop b 
    { 
     if(b == 1555) 
      goto loopDone; 
    } 

    for(int c = 2001; c <= 3000; c++) //loop c 
    { 
     . 
     . 
     . 
    } 
} 
loopDone: 
+14

+1: Questa è esattamente la condizione straordinaria per cui 'goto' è stato lasciato nella lingua per. –

+0

+1 @James. E la gente lo teme ancora inutilmente. Oh beh ... –

+0

@sundowatch, fino ad avere più loop annidati .... Questo metodo usa anche una variabile extra e ha più linee di codice (il che significa più spazio per i bug relativi ai typo). –

4
for(int a = 1; a <= 100; a++) //loop a (main loop) 
{ 
    for(int b = 1000; b <= 2000; b++) //loop b 
    { 
     if(b == 1555) 
      goto end; 
    } 

    for(int c = 2001; c <= 3000; c++) //loop c 
    { 
     . 
     . 
     . 
    } 
} 
end: 
4

L'unico modo per testa fuori di due di tali anse alla volta è un goto o un throw o un return e throw e return non può essere opportuno (specialmente throw, se la condizione isn' t eccezionale). In alternativa, è possibile impostare una sorta di condizione (bool breakout;) e continuare a interrompersi se è vero.

+2

Si può anche usare 'return' se il codice è refactored. Inoltre, poiché 'throw' solleva un'eccezione, questa sembra una cattiva pratica, a meno che non si effettui una pausa per una ragione" eccezionale "come dati corrotti, ecc. –

+0

@Justin: Grazie - incorporato nella mia risposta. –

1

utilizzare questo tipo di modello

for(int a = 1; a <= 100; a++) 
{ 
    int breakMain = 0; 
    for(int b = 1000; b <= 2000; b++) 
    { 
     if(b == 1555) 
     { 
      breakMain = 1; 
      break; 
     } 
    } 

    if(breakMain) 
     break; 

    for(int c = 2001; c <= 3000; c++) 
    { 
     . 
     . 
     . 
    } 
} 
3
  1. Utilizzare un goto:

    for(int a = 1; a <= 100; a++) //loop a (main loop) 
    { 
        for(int b = 1000; b <= 2000; b++) //loop b 
        { 
         if(b == 1555) 
          goto done; 
        } 
        for(int c = 2001; c <= 3000; c++) //loop c 
        { 
         . 
         . 
         . 
        } 
    } 
    done: 
    
  2. impostare un valore sentinella provato da ogni ciclo:

    bool sentinel = true ; 
    for(int a = 1; a <= 100 && sentinel ; a++) //loop a (main loop) 
    { 
        for(int b = 1000; b <= 2000 && sentinel; b++) //loop b 
        { 
         if(b == 1555) 
          sentinel = false; 
        } 
        for(int c = 2001; c <= 3000 && sentinel; c++) //loop c 
        { 
         . 
         . 
         . 
        } 
    } 
    
+0

hai dimenticato di interrompere il ciclo dopo sentinel è falso – kravemir

+0

Miro, tutti i loop terminano 9o non iniziano) se sentinel è falso. – tpdi

4

Se è opportuno, si potrebbe fare una funzione che è contenuto sono un ciclo e usano il ritorno.

public void bigLoop() 
{ 
    for(int a = 1; a <= 100; a++) 
    { 
     for(int b = 1000; b <= 2000; b++) 
     { 
      if(b == 1555) 
       return; 
     } 

     for(int c = 2001; c <= 3000; c++) 
     { 
      . 
      . 
      . 
     } 
    } 
}//bigLoop 
2

Una strategia semplice è quello di mettere il loop in una funzione separata e fare un ritorno al punto selezionato:

void func() 
{ 
    for(int a = 1; a <= 100; a++) //loop a (main loop) 
    { 
     for(int b = 1000; b <= 2000; b++) //loop b 
     { 
      if(b == 1555) 
       return; 
     } 

     for(int c = 2001; c <= 3000; c++) //loop c 
     { 
      . 
      . 
      . 
     } 
    } 
} 

Qualsiasi tipo di risultato può anche essere restituito con un valore di ritorno, o con un parametro di riferimento per la funzione.

+0

Questa sarebbe la mia soluzione. Il codice (tre loop, due incorporati nel primo) è abbastanza cattivo da giustificare l'astrazione in una subroutine comunque. –

23

O fare una delle quattro cose: utilizzare goto, utilizzare throw, utilizzare una bandiera o un refactoring.

Molti non saranno d'accordo con using goto, ma sometimes è una soluzione pulita. (La maggior parte delle volte non lo è, ma esiste per una ragione.) Tuttavia, trovo che l'uso di goto garantisce un refactoring.

La seconda soluzione è to throw un'eccezione speciale e quindi rilevarla appena fuori dal ciclo principale. Si tratta di un abuso del sistema di eccezione e fondamentalmente di un peggio goto; utilizzare un goto anziché questo.

La terza soluzione sarebbe utilizzare a flag di some sort. Questo è fondamentalmente un "più sicuro" goto, ma alcuni potrebbero obiettare che è un po 'più brutto. (Soprattutto con più livelli, anche se in questo caso la tua preoccupazione è quanto sia brutto il tuo codice.)

La soluzione che mi sento di raccomandare è il refactor. Qualunque cosa tu stia facendo, è troppo. Dovresti spostare i loop interni in una funzione e chiamare quella funzione. Il ritorno al ciclo principale è semplicemente un ritorno da quella funzione. (In altre parole "Il mio lavoro è fatto.")

+1

Non c'è niente di sbagliato con goto (se usato correttamente) Questo è uno di questi posti. È l'abuso di goto che dovrebbe essere temuto e la capacità di riconoscere l'abuso è così carente nelle nostre strutture di istruzione superiore. –

+0

@ Martin ovviamente ... ma se for-loops e intricate di goto fanno una funzione lunga, allora in effetti è davvero una cattiva idea. In questo esempio abbiamo tre loop convenzionali e un goto ... Penso che sia troppo. La mia visione personale. –

2

Il modo ideale sarebbe quello di ri-factor il codice in modo che non hai più bisogno di una tale complessa struttura nested-loop. A seconda di come appare il resto del codice, i tuoi loop b e c possono essere candidati per diventare funzioni individuali, se non l'intero ciclo a.

Dal momento che sembrano loop b e c iterare su intervalli adiacenti, perché non combinarli e ridurre un po 'il nesting del loop?

for (int a = 1; a <= 100; a++) //loop a (main loop) 
{ 
    int count = 1000; 
    while (count <= 3000) // combined loops 'b' and 'c' 
    { 
     if (count <= 2000) 
     { 
      // Old loop 'b' code 
      if (b == 1555) 
       goto fullbreak; 
     } 
     else 
     { 
      // Old loop 'c' code 
      ... 
     } 
     count++; 
    } 
} 
fullbreak: 

È inoltre possibile utilizzare una variabile di condizione al posto del goto. Se si desidera interrompere il vecchio ciclo b ma elaborare ancora il vecchio ciclo c, è sufficiente impostare count = 2001 all'interno del vecchio codice ciclo b.

Idealmente, si dovrebbe almeno essere in grado di ri-fattore questo per qualcosa di più simile

for (int a = 1; a <= 100; a++) //loop a (main loop) 
{ 
    if (process_inner_loop(pass, required, args)) 
     break; 
} 

dove la funzione process_inner_loop avvolge i tuoi originali due loop e restituisce diverso da zero se si vuole uscire il ciclo di chiusura. Ora, invece di utilizzare goto o condizione variabili, si può semplicemente return 1;.

4

\ (◕ ◡ ◕)/

[]() { 
    for(int a = 1; a <= 100; a++) //loop a (main loop) 
    { 
     for(int b = 1000; b <= 2000; b++) //loop b 
     { 
      if(b == 1555) 
       return; 
     } 

     for(int c = 2001; c <= 3000; c++) //loop c 
     { 
      . 
      . 
      . 
     } 
    } 
}(); 
+0

Otteresti l'ottimizzazione dei compilatori di lambas inline in casi come questo? – Gunslinger47

+1

In genere, qualsiasi compilatore moderno in linea tutte tranne le funzioni complesse/lunghe, * specialmente * se la definizione della funzione è visibile. (L'ottimizzazione del tempo di collegamento è relativamente nuova e più difficile.) Con questo, si noti che le lambda sono strutture nascoste uniche e la definizione completa è sempre disponibile ovunque venga utilizzata. Quindi sei praticamente garantito che Lambda sarà in linea. – GManNickG