438

Is it possible to use the break function to exit several nested for loops?

If so, how would you go about doing this? Can you also control how many loops the break exits?

9
  • 12
    Instead of using break or goto to exit multiple nested loops, you can enclose that particular logic in a function and use return to exit from multiple nested loops. This will maintain the aesthetics of your code and will prevent you from using goto which is a bad programming practice. Commented Aug 26, 2019 at 13:49
  • 8
    why goto is bad programming practice? it's widely used in kernel. Commented Feb 23, 2022 at 0:57
  • 1
    Goto statements reduces throughput of cpu pipelining. It makes branch prediction hard, Commented Jul 30, 2022 at 18:53
  • 1
    @CodeTalker so does any other statement that possibly exit the loop, whether is it goto, break, return... In practice this is not necessarily a big issue, as the branch that exits is executed only once after many executions of the branch that does not exit: any decent branch prediction algorithm will always predict the latter after a few iterations. Commented Apr 19, 2023 at 9:15
  • 1
    Does this answer your question? How to break out of nested loops? Commented Apr 27, 2024 at 12:13

19 Answers 19

365

No, don't spoil it with a break. This is the last remaining stronghold for the use of goto.

Sign up to request clarification or add additional context in comments.

11 Comments

The MISRA C++ coding standard allows the use of goto to cover this exact kind of situation.
Real programmers are not afraid to use goto. Done it for 25 years -- no regrets -- saved a ton of development time.
I agree. gotos are a must if you do not have 8K pixels across, and need to call a sequence of 30 Windows OS calls.
Or a simple "return" by putting the code in a function.
I came here looking for a way out of a switch statement inside a while loop. Logically, that's only one level of looping, but switch eats the break. This is the first goto I've written since I was writing in BASIC, circa 1985. (It's a very "hot" loop, even checking an extra boolean each time around costs 15-20%, so adding a done flag is not a good option. I just had to write this comment to cleanse my soul.)
|
301

AFAIK, C++ doesn't support naming loops, like Java and other languages do. You can use a goto, or create a flag value that you use. At the end of each loop check the flag value. If it is set to true, then you can break out of that iteration.

13 Comments

Don't be afraid to use a goto if that is the best option.
I'm a new C++ programmer (and one without any formal programming training) thus after reading about people's rants on goto. I'm hesitant on using it in fear my program might just suddenly explode and kill me. Other than that, when i used to write programs on my ti-83 (in boring math class of course), the functions the basic editor provided required the use of goto's.
@Faken: Two types of programmers use goto: Bad programmers, and pragmatic programmers. The former are self explanatory. The latter, which you would fit into if you choose to use them well, use a so called "evil" concept when it is the lesser of (two) evils. Read this for a better understanding of some C++ concepts that you might need to use from time to time (macros, goto's, preprocessor, arrays): parashift.com/c++-faq-lite/big-picture.html#faq-6.15
@Faken: There's nothing wrong with using goto. It's misusing a goto that is troublesome.
@Hooked: That's right, except that using goto rarely ever is the best option. Why not put the loops into their own function (inline, if you're concerned about speed) and return from this?
|
140

Just to add an explicit answer using 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
        }
      }
    }();
  }

Of course this pattern has a certain limitations and obviously C++11 only but I think it's quite useful.

8 Comments

This might confuse the reader into thinking the return causes the function the lambda is in to return, and not the lambda itself.
@Xunie: If your loop is so complicated, that you forget that you are in a lambda, it is time to put them in a different function, but for simple cases, this should work quite well.
You can capture the lambda in a RIIA template that gives it a name and calls it in dtor(aka scope gaurd). This would not add any performance gain but can improve readabilty and reduce the risk of missing the function call parenthesis.
this solution is not working when you also want a real return inside the loop... I mean: at one condition you just want to break out of 2 loops. at another condition you want to return out of the function. BTW: I really like this way of thinking! +1!
I tested this on godbolt and it appears to compile to identical code to using a goto! Another advantage of this solution over goto is that labels only work if they label a statement. For example, you can't write my_label: }
|
66

Another approach to breaking out of a nested loop is to factor out both loops into a separate function, and return from that function when you want to exit.

Of course, this brings up the other argument of whether you should ever explicitly return from a function anywhere other than at the end.

4 Comments

That's a C problem. With RIAA early return is not a problem as all the problems associated with early return are correctly handled.
I understand that proper application of RIAA can solve the resource cleanup problem in C++, but I have seen the philosophical argument against early return continue in other environments and languages. One system I worked on where the coding standard prohibited early return had functions littered with boolean variables (with names like continue_processing) that controlled the execution of blocks of code further down in the function.
What is RIAA? Is that anything like RAII? =D
Depends how many for loops he's got and how deep the nest goes... do you want the blue pill or the red pill?
38

break will exit only the innermost loop containing it.

You can use goto to break out of any number of loops.

Of course goto is often Considered Harmful.

is it proper to use the break function[...]?

Using break and goto can make it more difficult to reason about the correctness of a program. See here for a discussion on this: Dijkstra was not insane.

8 Comments

A good answer in that it explains that "goto is harmful" meme is strongly tied to the more generalized "control flow interruption is harmful" statement. It is meaningless to say "goto is harmful", and then turn around and recommend using break or return.
@Pavel: break and return have the advantage over goto that you don't need to hunt for a label in order to find where they go. Yes, underneath they are some kind of goto, but a very restricted one. They are a lot easier to decipher by a programmer's pattern-matching brain than the unrestricted goto. So IMO they are preferable.
@sbi: True, but break is still not part of structured programming. It is just better tolerated than a goto.
@KarlVoigtland the Dijkstra link is outdated; this appears to be working: blog.plover.com/2009/07
There is absolutely nothing wrong with using goto in this situation. A well placed goto is leaps and bounds better and more readable than many of the contorted solutions otherwise proposed.
|
36

How about this?

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

1 Comment

interesting approach but I definitely like the way ered @inf.ig.sh handles it. for (unsigned int y = 0; y < y_max && !gotoMainLoop; y++).
28

A concrete example using goto and a label to break out of a nested loop:

for (;;)
  for (;;)
    goto theEnd;
theEnd:

Comments

21

Although this answear was already presented, i think a good approach is to do the following:

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

}

4 Comments

which is good but still not so readable, i'd prefer goto in that case
this makes your code "quite" slow because the gotoMainLoop is checked every cycle
In this case, using the real goto makes core more readable and better-performing.
This is slower, less readable, harder to write, just overall worse in every way, than using goto instead.
17

I know this is an old thread but I feel this really needs saying and don't have anywhere else to say it. For everybody here, use goto. I just used it.

Like almost everything, goto is not 100% either/xor "bad" or "good". There are at least two uses where I'd say that if you use a goto for them - and don't use it for anything else - you should not only be 100% okay, but your program will be even more readable than without it, as it makes your intention that much clearer (there are ways to avoid it, but I've found all of them to be much clunkier):

  1. Breaking out of nested loops, and
  2. Error handling (i.e. to jump to a cleanup routine at the end of a function in order to return a failure code and deallocate memory.).

Instead of just dogmatically accepting rules like "so-so is 'evil'", understand why that sentiment is claimed, and follow the "why", not the letter of the sentiment. Not knowing this got me in a lot of trouble, too, to the point I'd say calling things dogmatically "evil" can be more harmful than the thing itself. At worst, you just get bad code - and then you know you weren't using it right so long as you heard to be wary, but if you are wracking yourself trying to satisfy the dogmatism, I'd say that's worse.

Why "goto" is called "evil" is because you should never use it to replace ordinary ifs, fors, and whiles. And why that? Try it, try using "goto" instead of ordinary control logic statements, all the time, then try writing the same code again with the control logic, and tell me which one looks nicer and more understandable, and which one looks more like a mess. There you go. (Bonus: try and add a new feature now to the goto-only code.) That's why it's "evil", with suitable scope qualification around the "evil". Using it to short-circuit the shortcomings of C's "break" command is not a problematic usage, so long as you make it clear from the code what your goto is supposed to accomplish (e.g. using a label like "nestedBreak" or something). Breaking out of a nested loop is very natural.

(Or to put it more simply: Use goto to break out of the loop. I'd say that's even preferable. Don't use goto to create the loop. That's "evil".)

And how do you know if you're being dogmatic? If following an "xyz is evil" rule leads your code to be less understandable because you're contorting yourself trying to get around it (such as by adding extra conditionals on each loop, or some flag variable, or some other trick like that), then you're quite likely being dogmatic.

There's no substitute for learning good thinking habits, moreso than good coding habits. The former are prior to the latter and the latter will often follow once the former are adopted. The problem is, however, that far too often I find, the latter are not explicated enough. Too many simply say "this is bad" and "this needs more thought" without saying what to think, what to think about, and why. And that's a big shame.

(FWIW, in C++, the need to break out of nested loops still exists, but the need for error codes does not: in that case, always use exceptions to handle error codes, never return them unless it's going to be so frequent that the exception throw and catch will be causing a performance problem, e.g. in a tight loop in a high demand server code, perhaps [some may say that 'exceptions' should be 'used rarely' but that's another part of ill-thought-out dogmatism: no, at least in my experience after bucking that dogma I find they make things much clearer - just don't abuse them to do something other than error handling, like using them as control flow; effectively the same as with "goto". If you use them all and only for error handling, that's what they're there for.].)

Comments

13

One nice way to break out of several nested loops is to refactor your code into a function:

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

6 Comments

...which is not a option if we have to pass 10-20 variables for stack framing this function.
@ПетърПетров then go for a lambda which is also better as you can define it exactly where you need it.
+1 for lambdas but overhaul in game engine core where even one stack frame is still a bottleneck. Sorry to tell, but lambdas are not so lightweight at least in MSVC 2010.
@ПетърПетров Then change the pair of functions into a class, and the stack variables into private members.
This only overcomplicates the already complex code :) Sometimes, goto is the only solution. Or if you write complex automata with "goto state X" documentation, then goto is actually making the code read as written in the document. Also, C# and go both have goto with a purpose: no language is turing-complete without a goto, and gotos are often the best used tools for writing intermediate translator or assembly-like code.
|
12

I'm not sure if it's worth it, but you can emulate Java's named loops with a few simple macros:

#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

Example usage:

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

Another example:

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

7 Comments

Although, it seems to let the outer loop to finish its current routine. It also doesn't directly "jump over" multiple levels of nested loops.
@radrow Can you show an example of the wrong behavior? Seems to work correctly for me.
Nevermind, I tested it and it works perfectly indeed. However, an explanation on how it works would be useful :)
@radrow There's not much to see here, once you expand the macros and look at the result. The loop body becomes if (false) {...} else {/*original loop body*/}, where the first branch that's never taken contains a few goto labels, that BREAK and CONTINUE jump to.
@Dumbled0re The variable is needed to stop you from using break/continue outside of this loop. The compiler refuses to goto into a scope if it requires creating a new variable, allowing you to break/continue only inside this if-else block.
|
8

goto can be very helpful for breaking nested loops

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

Comments

5

I do think a goto is valid in this circumstance:

To simulate a break/continue, you'd want:

Break

for ( ;  ;  ) {
    for ( ;  ;  ) {
        /*Code here*/
        if (condition) {
            goto theEnd;
        }
    }
}
theEnd:

Continue

for ( ;  ; ) {
    for ( ;  ;  ) {
        /*Code here*/
        if (condition) {
            i++;
            goto multiCont;
        }
    }
    multiCont:
}

2 Comments

"Continue" will not work there, because the iteration expression of the first loop won't be executed
I'm assuming that the iterator for the first loop is i. Hence i++ before the goto
3

The break statement terminates the execution of the nearest enclosing do, for, switch, or while statement in which it appears. Control passes to the statement that follows the terminated statement.

from msdn.

Comments

2

My suggestion is use a check variable to break a desired loop. The result code may not be so pleasant.
You can use preprocessors in order to make desired breaking under the hood. This approach can hides ugly codes and extra complexity.
For example, I created my custom break mechanism as follow:

Wanted code:

for (int i = 0; i < 100; i++) {
    for (int j = 0; j < 100; j++) {
        for (int k = 0; k < 100; k++) {
            //do something
            if (desiredCondition) {
                breakToLevel = 0;
            }
            if (breakToLevel < 3) {
                break;
            }
        }
        if (breakToLevel < 2) {
            break;
        }
    }
    if (breakToLevel < 1) {
        break;
    }
}

Defined macros:

#define BREAK_TO(L) breakToLevel = (L); 
#define CHECK_BREAK(L) if (breakToLevel < (L)) break; 

and result:

for (int i = 0; i < 100; i++) {
    for (int j = 0; j < 100; j++) {
        for (int k = 0; k < 100; k++) {
            //do something
            if (desiredCondition) {
                BREAK_TO(0)
            }
            CHECK_BREAK(3)
        }
        CHECK_BREAK(2)
    }
    CHECK_BREAK(1)
}

Comments

-1

I know this is old post . But I would suggest a bit logical and simpler answer.

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

2 Comments

That's not very scalable solution as j = conditionj won't work if you have a complex predicate instead of j < conditionj.
This is really error prone, if someone changes conditionj only only for the for statement, then bad things can happen...
-1

Break any number of loops by just one bool variable see below :

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

In this code we break; all the loops.

1 Comment

One extra check for every single iteration is much slower and more inefficient. I would take a simple goto over this any day.
-2

The most graceful way is to use exception.

Exception means encountering an abnormal situation, which can not only be a too bad situation but also be a too good situation.

For example you are looking for an element in a 3d array with 3 nested for-loops. The normal situation is "The current is NOT the one I'm looking for". The abnormal situation is "The current IS the one".

Remember the difference between error and exception. An exception doesn't have to be an error, it can be a good news.

Comments

-3

You can use 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

If you have to break out of several loops at once, it is often an exception anyways.

8 Comments

@hkBattousai The solution has down votes because it's using an exception to control the execution flow. As the name suggests, exceptions should only be used on exceptional cases.
@HelioSantos Isn't this an exceptional situation for which the language is not supplying proper solution?
The performance impact of the throw is huge for something that is not an unrecoverable error 99% of the time.
@hkbattousai The language does provide solutions, such as using a a test condition, or using a goto.
Also, if another exception was thrown from that code block, you would catch it, thinking it is the control flow one and it would get propagated/handled properly.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.