¿Es posible usar la break
función para salir de varios for
bucles anidados ?
Si es así, ¿cómo harías para hacer esto? ¿Puedes controlar también cuántos bucles break
salen?
¿Es posible usar la break
función para salir de varios for
bucles anidados ?
Si es así, ¿cómo harías para hacer esto? ¿Puedes controlar también cuántos bucles break
salen?
Respuestas:
AFAIK, C ++ no admite bucles de nombres, como lo hacen Java y otros lenguajes. Puede usar un goto o crear un valor de marca que use. Al final de cada ciclo, verifique el valor del indicador. Si se establece en verdadero, puede salir de esa iteración.
goto
si esa es la mejor opción.
goto
: programadores malos y programadores pragmáticos. Los primeros se explican por sí mismos. Este último, en el que encajaría si elige usarlos bien, utiliza un concepto llamado "malvado" cuando es el menor de (dos) males. Lea esto para comprender mejor algunos conceptos de C ++ que puede necesitar usar de vez en cuando (macros, goto's, preprocesador, matrices): parashift.com/c++-faq-lite/big-picture.html#faq-6.15
goto
raramente es la mejor opción. ¿Por qué no poner los bucles en su propia función ( inline
si te preocupa la velocidad) y return
de esto?
No, no lo estropees con un break
. Este es el último bastión restante para el uso de goto
.
Solo para agregar una respuesta explícita usando lambdas:
for (int i = 0; i < n1; ++i) {
[&] {
for (int j = 0; j < n2; ++j) {
for (int k = 0; k < n3; ++k) {
return; // yay we're breaking out of 2 loops here
}
}
}();
}
Por supuesto, este patrón tiene ciertas limitaciones y obviamente solo C ++ 11, pero creo que es bastante útil.
Otro enfoque para salir de un bucle anidado es factorizar ambos bucles en una función separada, y return
desde esa función cuando desee salir.
Por supuesto, esto trae a colación el otro argumento de si alguna vez debería explícitamente return
desde una función en cualquier lugar que no sea al final.
continue_processing
) que controlaban la ejecución de bloques de código más abajo en la función.
break saldrá solo del bucle más interno que lo contiene.
Puede usar goto para salir de cualquier número de bucles.
Por supuesto, ir a menudo se considera perjudicial .
¿Es apropiado usar la función de interrupción [...]?
Usar break y goto puede hacer que sea más difícil razonar sobre la corrección de un programa. Vea aquí para una discusión sobre esto: Dijkstra no estaba loco .
break
o return
.
break
y return
tiene la ventaja de goto
que no necesita buscar una etiqueta para saber a dónde van. Sí, debajo hay algún tipo de goto
, pero muy restringido. Son mucho más fáciles de descifrar por el cerebro de coincidencia de patrones de un programador que los no restringidos goto
. Por lo tanto, son preferibles.
goto
.
Aunque esta respuesta ya se presentó, creo que un buen enfoque es hacer lo siguiente:
for(unsigned int z = 0; z < z_max; z++)
{
bool gotoMainLoop = false;
for(unsigned int y = 0; y < y_max && !gotoMainLoop; y++)
{
for(unsigned int x = 0; x < x_max && !gotoMainLoop; x++)
{
//do your stuff
if(condition)
gotoMainLoop = true;
}
}
}
gotoMainLoop
se verifica cada ciclo
goto
hace que el núcleo sea más legible y tenga un mejor rendimiento.
¿Qué tal esto?
for(unsigned int i=0; i < 50; i++)
{
for(unsigned int j=0; j < 50; j++)
{
for(unsigned int k=0; k < 50; k++)
{
//Some statement
if (condition)
{
j=50;
k=50;
}
}
}
}
Un ejemplo de código con goto
una etiqueta para salir de un bucle anidado:
for (;;)
for (;;)
goto theEnd;
theEnd:
Una buena manera de salir de varios bucles anidados es refactorizar su código en una función:
void foo()
{
for(unsigned int i=0; i < 50; i++)
{
for(unsigned int j=0; j < 50; j++)
{
for(unsigned int k=0; k < 50; k++)
{
// If condition is true
return;
}
}
}
}
Goto puede ser muy útil para romper bucles anidados
for (i = 0; i < 1000; i++) {
for (j = 0; j < 1000; j++) {
for (k = 0; k < 1000; k++) {
for (l = 0; l < 1000; l++){
....
if (condition)
goto break_me_here;
....
}
}
}
}
break_me_here:
// Statements to be executed after code breaks at if condition
Creo que un goto
es válido en esta circunstancia:
Para simular un break
/continue
, querrías:
for ( ; ; ) {
for ( ; ; ) {
/*Code here*/
if (condition) {
goto theEnd;
}
}
}
theEnd:
for ( ; ; ) {
for ( ; ; ) {
/*Code here*/
if (condition) {
i++;
goto multiCont;
}
}
multiCont:
}
i
. Por lo tanto, i++
antes del goto
Otros lenguajes, como PHP, aceptan un parámetro para la interrupción (es decir, la interrupción 2;) para especificar la cantidad de niveles de bucle anidados de los que desea salir, pero C ++ no lo hace. Tendrá que resolverlo usando un booleano que establezca en falso antes del ciclo, establezca en verdadero en el ciclo si desea romper, más un corte condicional después del ciclo anidado, verificando si el booleano se estableció en verdadero y romper si es así.
Sé que esta es una publicación antigua. Pero sugeriría una respuesta un poco lógica y más simple.
for(unsigned int i=0; i < 50; i++)
{
for(unsigned int j=0; j < conditionj; j++)
{
for(unsigned int k=0; k< conditionk ; k++)
{
// If condition is true
j= conditionj;
break;
}
}
}
j = conditionj
que no funcionará si tiene un predicado complejo en lugar de j < conditionj
.
Divida cualquier número de bucles por una sola bool
variable, vea a continuación:
bool check = true;
for (unsigned int i = 0; i < 50; i++)
{
for (unsigned int j = 0; j < 50; j++)
{
for (unsigned int k = 0; k < 50; k++)
{
//Some statement
if (condition)
{
check = false;
break;
}
}
if (!check)
{
break;
}
}
if (!check)
{
break;
}
}
En este código tenemos break;
todos los bucles.
No estoy seguro de si vale la pena, pero puede emular los bucles con nombre de Java con algunas macros simples:
#define LOOP_NAME(name) \
if ([[maybe_unused]] constexpr bool _namedloop_InvalidBreakOrContinue = false) \
{ \
[[maybe_unused]] CAT(_namedloop_break_,name): break; \
[[maybe_unused]] CAT(_namedloop_continue_,name): continue; \
} \
else
#define BREAK(name) goto CAT(_namedloop_break_,name)
#define CONTINUE(name) goto CAT(_namedloop_continue_,name)
#define CAT(x,y) CAT_(x,y)
#define CAT_(x,y) x##y
Ejemplo de uso:
#include <iostream>
int main()
{
// Prints:
// 0 0
// 0 1
// 0 2
// 1 0
// 1 1
for (int i = 0; i < 3; i++) LOOP_NAME(foo)
{
for (int j = 0; j < 3; j++)
{
std::cout << i << ' ' << j << '\n';
if (i == 1 && j == 1)
BREAK(foo);
}
}
}
Otro ejemplo:
#include <iostream>
int main()
{
// Prints:
// 0
// 1
// 0
// 1
// 0
// 1
int count = 3;
do LOOP_NAME(foo)
{
for (int j = 0; j < 3; j++)
{
std::cout << ' ' << j << '\n';
if (j == 1)
CONTINUE(foo);
}
}
while(count-- > 1);
}
Puedes usar try ... catch.
try {
for(int i=0; i<10; ++i) {
for(int j=0; j<10; ++j) {
if(i*j == 42)
throw 0; // this is something like "break 2"
}
}
}
catch(int e) {} // just do nothing
// just continue with other code
Si tiene que salir de varios bucles a la vez, a menudo es una excepción.
Romper un bucle for es un poco extraño para mí, ya que la semántica de un bucle for generalmente indica que se ejecutará un número específico de veces. Sin embargo, no es malo en todos los casos; si está buscando algo en una colección y quiere romperlo después de encontrarlo, es útil. Sin embargo, la ruptura de bucles anidados no es posible en C ++; es en otros idiomas mediante el uso de un descanso etiquetado. Puede usar una etiqueta y un goto, pero eso podría provocarle acidez estomacal por la noche ... Sin embargo, parece la mejor opción.