2010-08-09 14 views
9

estoy preparando algo de código:C++: romper el bucle principal

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 
    { 
     . 
     . 
     . 
    } 
} 

Quiero romper el bucle principal (variable de bucle int a) mediante una instrucción break; en el b bucle (variable de bucle int b).

¿Cómo puedo hacerlo?

+3

Si se me ha informado correctamente, algunos lenguajes de apoyar la construcción de romper 'N' donde 'n' es el número de bucles anidados para salir de. ¿Estoy en lo cierto? –

+0

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

+1

@Andreas: este no es uno de ellos. @sundowatch: Refactorice su código, no solo resolverá su problema sino que su código será más limpio y más fácil de mantener. – GManNickG

Respuesta

20

recomiendo refactorización su código en una función. A continuación, puede simplemente return de esa función en lugar de utilizar 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 
     } 

     . 
     . 
     . 
    } 
} 

Este - o tal vez incluso una refactorización más complicado de su código - debe prestarse a una solución limpia, elegante. Por otra parte, si lo que desea una solución rápida se puede utilizar una variable de condición:

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; 

    . 
    . 
    . 
} 

Otros han sugerido el uso de goto. Si bien esa es otra solución rápida, recomiendo encarecidamente que no lo haga, especialmente si está trabajando en un entorno riguroso en el que el código será revisado por pares y utilizado durante años en el futuro.

En mi opinión el enfoque goto es un poco más difícil de mantener que una refactorización función/retorno, sobre todo más adelante, cuando otra persona realiza cambios en el código. Además, deberá justificar el goto con cualquier otra persona del equipo que se tropiece con el código.

+9

Esto funciona en dos niveles, pero no escala mucho más allá de eso. Este es el caso donde aprietas los dientes y usas 'goto'. –

+14

@James: O refactoriza tu desagradable código multinivel y no hagas ninguna de las dos cosas. – GManNickG

+3

@GMan: De acuerdo. Mi solución típica sería poner el cuerpo del bucle externo en una subrutina, y usar "retorno". –

34

Utilice 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: Esta es exactamente la condición extraordinaria que 'goto' se dejó en el lenguaje para. –

+0

+1 @Juegos. Y la gente todavía teme innecesariamente. Oh, bueno ... –

+0

@sundowatch, hasta que tenga más bucles anidados ... Ese método también usa una variable adicional y tiene más líneas de código (lo que significa más espacio para errores relacionados con errores tipográficos). –

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

La única forma de salir de dos de tales bucles a la vez es una goto o una throw o una return, y throw y return pueden no ser apropiados (en particular throw, si la condición ISN' t excepcional). Alternativamente, puede establecer algún tipo de condición (bool breakout;) y seguir rompiendo si es verdad.

+2

También puede usar 'return' si el código se refactoriza. Además, dado que 'throw' plantea una excepción, esto parece una mala práctica a menos que el corte se realice por un motivo" excepcional ", como datos corruptos, etc. –

+0

@Justin: gracias - incorporé eso en mi respuesta. –

1

Usar este tipo de patrón

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. Utilice 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. establecer un valor centinela probado por cada bucle:

    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

se ha olvidado de romper el bucle después de que centinela sea falso – kravemir

+0

Miro, todos los bucles terminan 9o no comienzan) si el centinela es falso. – tpdi

4

Si es apropiado, se puede hacer una función que está contenido son el a loop, y use return.

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 estrategia simple es poner el lazo en una función independiente y hacer una vuelta en el punto seleccionado:

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 
     { 
      . 
      . 
      . 
     } 
    } 
} 

Cualquier tipo de resultado también puede ser devuelto con un valor de retorno, o con un parámetro de referencia para la función.

+0

Esta sería mi solución. El código (tres bucles, dos incrustados en el primero) es lo suficientemente desagradable como para justificar la abstracción en una subrutina de todos modos. –

23

Haga cualquiera de estas cuatro cosas: use goto, use throw, use una bandera o refactor.

Muchos estarán en desacuerdo con using goto, pero sometimes es una solución limpia. (La mayoría de las veces, no lo es, pero existe por una razón). Sin embargo, creo que el uso de goto garantiza un refactor.

La segunda solución es to throw alguna excepción especial y luego la captura justo fuera del bucle principal. Esto es un abuso del sistema de excepción y básicamente un peor goto; utilice un goto en lugar de esto.

La tercera solución sería usar a flag de some sort. Esto es básicamente un "seguro" goto, pero algunos podrían argumentar que es un poco más feo. (Especialmente con niveles múltiples. Aunque en tal caso su preocupación es qué tan feo es su código)

La solución que recomendaría es refactor. Lo que sea que estés haciendo, es demasiado. Debería mover los bucles internos a una función y llamar a esa función. Volver al bucle principal es simplemente un retorno de esa función. (En otras palabras, "Mi trabajo está hecho")

+1

No hay nada de malo con goto (si se usa correctamente) Este es uno de estos lugares. Es el abuso de goto lo que debe temerse y la capacidad de reconocer el abuso es tan escasa en nuestras instalaciones de educación superior. –

+0

@Martin, por supuesto ... pero si for-loops y goto's intrincados hacen una función larga, entonces de hecho es una mala idea. En este ejemplo tenemos tres intrincados bucles for y un goto ... Creo que es demasiado. Mi punto de vista personal. –

2

La forma ideal sería volver a factorizar el código para que ya no necesite una estructura de bucle anidado tan complicada. Dependiendo de cómo se vea el resto del código, los bucles b y c pueden ser candidatos para convertirse en funciones individuales, si no todo el bucle a.

Dado que parece que los bucles b y c iteran sobre rangos adyacentes, ¿por qué no combinarlos y reducir un poco la anidación del bucle?

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: 

También puede utilizar una variable de estado en lugar del goto. Si desea salir del antiguo bucle b pero aún procesar el antiguo bucle c, simplemente configure count = 2001 dentro del antiguo código de bucle b.

Lo ideal sería al menos ser capaz de volver a este factor a algo más parecido a

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

donde la función process_inner_loop envuelve sus dos bucles originales y devuelve un valor no nulo si desea salir de el bucle adjunto. Ahora, en lugar de usar goto o variables de condición, simplemente puede 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

¿Se optimizarían los compiladores en línea lambas en casos como este? – Gunslinger47

+1

Normalmente, cualquier compilador moderno alineará todas las funciones, excepto las complejas/largas, * especialmente * si la definición de la función es visible. (La optimización del tiempo de enlace es relativamente nueva y más difícil.) Con eso, tenga en cuenta que las lambda son estructuras ocultas únicas, y la definición completa está siempre disponible donde sea que se use. Así que está prácticamente garantizado que la lambda estará en línea. – GManNickG

Cuestiones relacionadas