How to break out of a loop from inside a switch?
Solution 1
Premise
The following code should be considered bad form, regardless of language or desired functionality:
while( true ) {
}
Supporting Arguments
The while( true )
loop is poor form because it:
- Breaks the implied contract of a while loop.
- The while loop declaration should explicitly state the only exit condition.
- Implies that it loops forever.
- Code within the loop must be read to understand the terminating clause.
- Loops that repeat forever prevent the user from terminating the program from within the program.
- Is inefficient.
- There are multiple loop termination conditions, including checking for "true".
- Is prone to bugs.
- Cannot easily determine where to put code that will always execute for each iteration.
- Leads to unnecessarily complex code.
- Automatic source code analysis.
- To find bugs, program complexity analysis, security checks, or automatically derive any other source code behaviour without code execution, specifying the initial breaking condition(s) allows algorithms to determine useful invariants, thereby improving automatic source code analysis metrics.
- Infinite loops.
- If everyone always uses
while(true)
for loops that are not infinite, we lose the ability to concisely communicate when loops actually have no terminating condition. (Arguably, this has already happened, so the point is moot.)
- If everyone always uses
Alternative to "Go To"
The following code is better form:
while( isValidState() ) {
execute();
}
bool isValidState() {
return msg->state != DONE;
}
Advantages
No flag. No goto
. No exception. Easy to change. Easy to read. Easy to fix. Additionally the code:
- Isolates the knowledge of the loop's workload from the loop itself.
- Allows someone maintaining the code to easily extend the functionality.
- Allows multiple terminating conditions to be assigned in one place.
- Separates the terminating clause from the code to execute.
- Is safer for Nuclear Power plants. ;-)
The second point is important. Without knowing how the code works, if someone asked me to make the main loop let other threads (or processes) have some CPU time, two solutions come to mind:
Option #1
Readily insert the pause:
while( isValidState() ) {
execute();
sleep();
}
Option #2
Override execute:
void execute() {
super->execute();
sleep();
}
This code is simpler (thus easier to read) than a loop with an embedded switch
. The isValidState
method should only determine if the loop should continue. The workhorse of the method should be abstracted into the execute
method, which allows subclasses to override the default behaviour (a difficult task using an embedded switch
and goto
).
Python Example
Contrast the following answer (to a Python question) that was posted on StackOverflow:
- Loop forever.
- Ask the user to input their choice.
- If the user's input is 'restart', continue looping forever.
- Otherwise, stop looping forever.
- End.
while True:
choice = raw_input('What do you want? ')
if choice == 'restart':
continue
else:
break
print 'Break!'
Versus:
- Initialize the user's choice.
- Loop while the user's choice is the word 'restart'.
- Ask the user to input their choice.
- End.
choice = 'restart';
while choice == 'restart':
choice = raw_input('What do you want? ')
print 'Break!'
Here, while True
results in misleading and overly complex code.
Solution 2
You can use goto
.
while ( ... ) {
switch( ... ) {
case ...:
goto exit_loop;
}
}
exit_loop: ;
Solution 3
An alternate solution is to use the keyword continue
in combination with break
, i.e.:
for (;;) {
switch(msg->state) {
case MSGTYPE:
// code
continue; // continue with loop
case DONE:
break;
}
break;
}
Use the continue
statement to finish each case label where you want the loop to continue and use the break
statement to finish case labels that should terminate the loop.
Of course this solution only works if there is no additional code to execute after the switch statement.
Solution 4
A neatish way to do this would be to put this into a function:
int yourfunc() {
while(true) {
switch(msg->state) {
case MSGTYPE: // ...
break;
// ... more stuff ...
case DONE:
return;
}
}
}
Optionally (but 'bad practices'): as already suggested you could use a goto, or throw an exception inside the switch.
Solution 5
AFAIK there is no "double break" or similar construct in C++. The closest would be a goto
- which, while it has a bad connotation to its name, exists in the language for a reason - as long as it's used carefully and sparingly, it's a viable option.
jrharshath
Updated on July 08, 2022Comments
-
jrharshath almost 2 years
I'm writing some code that looks like this:
while(true) { switch(msg->state) { case MSGTYPE: // ... break; // ... more stuff ... case DONE: break; // **HERE, I want to break out of the loop itself** } }
Is there any direct way to do that?
I know I can use a flag, and break from the loop by putting a conditional break just after the switch. I just want to know if C++ has some construct for this already.
-
Tal Pressman over 14 yearsWhy do you need a conditional break after the switch? Just change your while from while(true) to while(flag)...
-
Alterlife over 14 years@Dave_Jarvis I assume that this is a simplified version that he has put in here to illustrate what he was trying to do.
-
Jonathan Leffler over 14 yearsSee: Code Complete (2nd Edn). See also 'Structured Programming with goto statements' by D E Knuth (pplab.snu.ac.kr/courses/adv_pl05/papers/p261-knuth.pdf).
-
Jonathan Leffler over 14 years@Tal Pressman et al: it looks like it could be a state table machine to me, with one case for each state - including a DONE state in which the code should exit. However, that could perhaps be handled by '
while (msg->state != DONE)
' for the loop control. -
Dave Jarvis over 14 years@Jonathan. Yes, exactly. I would go one further and separate the concerns of the loop's terminating condition from the loop itself (extract it to a method).
-
sbi over 14 yearsIf you are one of these programmers that produce functions which are several pages long, you'll find
goto
appealing and, sometimes, the only clean way out. If you tend to organize your code into small functions which are only a few lines long and do one single thing each, you will never run into this problem. (Incidentally your code will be easier to read, too.) -
sbi over 14 years@hacker: Well, if you can't see the subway station in front of you due to all the smoke, that advice might not be all that bad.
:)
-
Dmitry Vyal over 10 yearsSometimes it's convenient to call return from a case. Not pretty, but works.
-
xcorat over 7 yearsYou can always use if-else, unless you have too many cases..!
-
Steven Spark over 4 years@sbi If you are one of those programmers who only write functions which are only a few lines long, then by definition you are not using/writing (well formatted) switch-case statements ;) (depending on your definition of "few") But yes, you can usually break it up a bit (move the while loop into its own function, use return)... though it won't always make the code more readable. If I grouped every pair of statements into a function then I could write code that reads like a binary tree :) Just try writing readable chunks that belong together so looking up functions doesn't break flow of reading.
-
sbi over 4 years@Steven Who said I group "every pair of statements into a function"?
-
Steven Spark almost 4 years@sbi I don't know? Who said it? I for sure didn't say that you did. I just tried to illustrate my point, that shorter doesn't always result more readable code. But it usually does, so it's a good practice to divide code to the shortest possible complete chunks, but not shorter IMO. [ I don't know how to move this conversation off of this comment thread, but I'm curious what you think about libtomcrypt's use of gotos. Do you have an elegant, more readable way of doing it? ]
-
-
Fragsworth over 14 yearsJust don't go wild with that keyword.
-
mmx over 14 yearsIt's funny I get downvoted because people don't like
goto
. The OP clearly mentioned without using flags. Can you suggest a better way, considering the OP's limitation? :) -
dnatoli over 14 yearsPretty sure that is the only way to do it but unless you want spaghetti code, I would steer clear of goto.
-
quamrana over 14 years+1:
goto
seems to be an ideal solution here. It would be improved if thewhile
loop were also the sole constituent of a function or method. -
mmx over 14 yearsI don't say it's necessarily the ideal solution. Refactoring the code is probably a better idea. However, I believe it's a valid answer to this question.
-
Clement Herreman over 14 yearsException should be used to, well, throw an exception, not a well know behavior of a function.
-
dalle over 14 yearsI agree with Afterlife: Put it in a function.
-
Kirill V. Lyadvinsky over 14 years@Mehrdad, I suggested a way in my answer. But it is just for fun :)
-
Michael Krelin - hacker over 14 yearsupvoted just t to compensate mindless goto haters. I guess Mehrdad knew he's going to lose a couple of points for suggesting sensible solution here.
-
Gorpik over 14 years+1. I understand this is more of a theoretical than a practical question; it clearly asks for a jump instruction. Given that break, continue and return are unsuitable, the only answer is the general jump: goto. This said, while (flag) would be a superior construct, but not what the OP asked for.
-
quamrana over 14 yearsYeah, but I like exceptions even less ;-)
-
John Carter over 14 yearsUsing an exception to emulate a goto is of course worse than actually using a goto! It will probably also be significantly slower.
-
Kirill V. Lyadvinsky over 14 years@Downvoter: It is because I state, that you shouldn't use exception, or because I suggest refactoring?
-
SingleNegationElimination over 14 yearsYou know I was actually a bit surprised to see a
goto
answer. I'm glad you did, though, so I don't gotta. +1 -
Jonathan Leffler over 14 yearsSee: Code Complete (2nd Edn). See also 'Structured Programming with goto statements' by D E Knuth (pplab.snu.ac.kr/courses/adv_pl05/papers/p261-knuth.pdf).
-
Jonathan Leffler over 14 yearsNot the down-voter - but... Your answer isn't clear whether you are proposing or condemning the idea of using an exception to exit the loop. Maybe the first sentence should be: "Even if you don't like
goto
, do not use an exception to exit a loop:"? -
Paulius over 14 yearsAlthough the title of this answer may not be the best - I'd say the content is very good and well explained. You'd never see while(true) in any of my code and this post explains all of the reasons why. Up vote from me.
-
Kirill V. Lyadvinsky over 14 years@Jonathan Leffler, Thanks, you showed the sample of valuable comment. updated the answer keeping in mind your comments.
-
sbi over 14 yearsThe idea that
while(true)
should be harmful seems bizarre to me. There's loops that check before they execute, there's those that check afterwards, and there's those that check in the middle. Since the latter don't have syntactic construct in C and C++, you'll have to usewhile(true)
orfor(;;)
. If you consider this wrong, you haven't given enough thought to the different kind of loops yet. -
David Thornley over 14 yearsReasons why I disagree: while(true) and for(;;;) are not confusing (unlike do{}while(true)) because they state what they're doing right up front. It is actually easier to look for "break" statements than parse an arbitrary loop condition and look for where it's set, and no harder to prove correctness. The argument about where to put code is just as intractable in the presence of a continue statement, and not much better with if statements. The efficiency argument is positively silly.
-
David Thornley over 14 yearsThis is one of the very few areas I'd consider a goto. It's forward in direction and goes out of scopes rather than in. It implements a very easily understood concept. The problem with goto is that it's easy to use in an unstructured way (and that so few people use it that it's rather obscure). This is, in my opinion, an acceptable and appropriate use.
-
David Thornley over 14 yearsThrowing an exception is substituting a COMEFROM for a GOTO. Don't do it. The goto works much better.
-
Johannes Schaub - litb over 14 years+1, there is no better way imho, even when considering the OPs limitations. Flags are ugly, break up logic across the whole loop and thus more difficult to grasp.
-
David Thornley over 14 yearsWhenever you see "while(true)", you can think of a loop that has internal termination conditions, which are no harder than arbitrary end conditions. Simply, a "while(foo)" loop, where foo is a boolean variable set in an arbitrary way, is no better than "while(true)" with breaks. You have to look through the code in both cases. Putting forth a silly reason (and microefficiency is a silly argument) doesn't help your case, by the way.
-
David Thornley over 14 years@Dave Jarvis: We do seem to have some serious differences of opinion. Personally, I don't see that typing /break is any harder than looking for where a sentinel variable changes (and the original example would require a sentinel variable if there was any processing to be done if msg->state == DONE). I looked for efficiencies in the Knuth article, and found stuff that was basically irrelevant (12% improvement from adding a sentinel value) and stuff that was valid 35 years ago. I saw nothing applicable to while(true) at all.
-
David Thornley over 14 yearsUnfortunately, your memory is faulty. It would be a nice feature, on those rare occasions where it would be useful. (I've seen proposals for number of levels to break from, but those look to me like bugs waiting to happen.)
-
Andrei Vajna II over 14 yearsThat must have been Java, then. Thanks for answering. And, of course, you're right with the rest, too.
-
sbi over 14 yearsWhile this is indeed very elegant, it has the disadvantage that most developers first have to look at it for a minute in order to understand how/whether this works.
:(
-
Mark A. Donohoe about 13 yearsUm... you could be even simpler by putting that condition in the while argument. I mean that's what it's there for! :)
-
unsynchronized over 11 yearsat the end of the day, without the goto construct, all languages fail. high level languages obfuscate it, but if you look hard enough under the hood, you will find every loop, or condition boils down to conditional and unconditional branches. we fool ourselves by using for,while,until, switch,if keywords, but eventually they all utilise GOTO (or JMP) in one way or the other. you can delude yourself, inventing all sorts of clever way to hide it, or you can just be pragmatically honest, and use goto, where appropriate, and sparingly.
-
Dan Hulme over 11 yearsAll the breaks in that code sample break out of the switch statement.
-
nawfal over 10 yearsThe last sentence is what makes this not so great
:(
Otherwise a very clean implementation. -
Daniel over 7 years@Dave Jarvis: the
continue
in your python code is totally unnecessary. Initializingchoice
with some dummy value is the error prone part. -
Dave Branton about 7 yearsPersonally, I have never, and will never, use a goto. Unless I'm writing assembly, where it's spelled JMP.
-
Vagish over 5 yearsSingle process, single thread bare metal embedded code is always inside while (1).
-
Admin almost 5 yearsProbably the person meant without flags, without goto. Morally, there should be a way to break from a loop and switch statement! Why did they use the same keyword????
-
Admin almost 5 yearsWhen you think about it, no computer code is good. We are only trained to understand it. For example xml looked like garbage until I learnt it. Now it is less garbage looking. for(int x=0; x<10; ++x, moveCursor(x,y)) actually caused a logic error in my program. I forgot that the update condition happened at the end.
-
Alex Leibowitz almost 5 yearsAs a courtesy to people reading this answer, I would avoid commenting on the quality of the good that produced the question and stick to answering the question itself. The question is a variation on the following, which I believe is a feature of many languages: you have a loop nested inside of another loop. You want to break out of the outer loop from the inner loop. How is this done?
-
Askaga over 4 yearsThis answer completely ignores the very valid case of a loop with termination condition somewhere in the middle (if that wasn't an appropriate use case we wouldn't even have a break keyword after all) for the sake of demonizing goto. Transforming a
while(true)
loop with a break in the middle into awhile(cond)
ordo{}while(cond)
form would require either an artificial flag or code duplication, both of which are harder to read and argue about. Finally, if you are worried about performance implications ofwhile(true)
you can always change it tofor(;;)
-
Steven Spark over 4 yearsFor all the goto haters: opensource.apple.com/source/xnu/xnu-792/libkern/stdio/… , elixir.bootlin.com/linux/latest/source/drivers/usb/core/usb.c github.com/embeddedartists/labtool/blob/master/fw/Lib_USB/… verysource.com/code/30591516_1/usbcore.c.html :) Goto can be useful for freeing up resources after detecting error, zeroing out buffers after crypt (PolarSSL, libtomcrypt)... without expensive exceptions or even C++...
-
Kamil over 3 yearsNeat! I was about to write the same answer.
-
Jean-David Lanz over 2 yearsBrilliant in its simplicity. Just what I needed. Thanks!