171

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.

6
  • 23
    Why do you need a conditional break after the switch? Just change your while from while(true) to while(flag)... Commented Sep 14, 2009 at 7:02
  • 1
    @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. Commented Sep 14, 2009 at 7:54
  • 6
    If 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.) Commented Sep 14, 2009 at 9:40
  • Sometimes it's convenient to call return from a case. Not pretty, but works. Commented Aug 20, 2013 at 14:48
  • You can always use if-else, unless you have too many cases..! Commented Jan 25, 2017 at 15:41

21 Answers 21

236

You can use goto.

while ( ... ) {
   switch( ... ) {
     case ...:
         goto exit_loop;

   }
}
exit_loop: ;
Sign up to request clarification or add additional context in comments.

15 Comments

Just don't go wild with that keyword.
It'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? :)
upvoted 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.
+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.
at 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.
|
84

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.

3 Comments

While 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. :(
The last sentence is what makes this not so great :( Otherwise a very clean implementation.
When 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.
55

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.)

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:

  1. Isolates the knowledge of the loop's workload from the loop itself.
  2. Allows someone maintaining the code to easily extend the functionality.
  3. Allows multiple terminating conditions to be assigned in one place.
  4. Separates the terminating clause from the code to execute.
  5. 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:

  1. Loop forever.
  2. Ask the user to input their choice.
  3. If the user's input is 'restart', continue looping forever.
  4. Otherwise, stop looping forever.
  5. End.
Code
while True: 
    choice = raw_input('What do you want? ')

    if choice == 'restart':
        continue
    else:
        break

print 'Break!' 

Versus:

  1. Initialize the user's choice.
  2. Loop while the user's choice is the word 'restart'.
  3. Ask the user to input their choice.
  4. End.
Code
choice = 'restart';

while choice == 'restart': 
    choice = raw_input('What do you want? ')

print 'Break!'

Here, while True results in misleading and overly complex code.

10 Comments

The 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 use while(true) or for(;;). If you consider this wrong, you haven't given enough thought to the different kind of loops yet.
Reasons 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.
Whenever 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.
@Dave: I gave a reason: It's the only way to get a loop that checks the condition in the middle. Classic example: while(true) {string line; std::getline(is,line); if(!is) break; lines.push_back(line);} Of course I could transform this to a preconditioned loop (using std::getline as the loop condition), but this has disadvantages on its own (line would have to be a variable outside the loop's scope). And if I did, I would have to ask: Why do we have three loops anyway? We could always transform everything into a preconditioned loop. Use what fits best. If while(true) fits, then use it.
As 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?
|
29

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.

5 Comments

Exception should be used to, well, throw an exception, not a well know behavior of a function.
I agree with Afterlife: Put it in a function.
Throwing an exception is really evil in this case. It means "I want to use a goto, but I read somewhere that I should not use them, so I'll go with a subterfuge and pretend to look smart".
I agree that throwing an exception or using a goto is a terrible idea, but they are working options and have been listed as such in my answer.
Throwing an exception is substituting a COMEFROM for a GOTO. Don't do it. The goto works much better.
17

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.

Comments

13

You could put your switch into a separate function like this:

bool myswitchfunction()
{
    switch(msg->state) {
    case MSGTYPE: // ... 
        break;
    // ... more stuff ...
    case DONE:
        return false; // **HERE, I want to break out of the loop itself**
    }
    return true;
}

while(myswitchfunction())
    ;

Comments

8

Even if you don't like goto, do not use an exception to exit a loop. The following sample shows how ugly it could be:

try {
  while ( ... ) {
    switch( ... ) {
      case ...:
        throw 777; // I'm afraid of goto
     }
  }
}
catch ( int )
{
}

I would use goto as in this answer. In this case goto will make code more clear then any other option. I hope that this question will be helpful.

But I think that using goto is the only option here because of the string while(true). You should consider refactoring of your loop. I'd suppose the following solution:

bool end_loop = false;
while ( !end_loop ) {
    switch( msg->state ) {
    case MSGTYPE: // ... 
        break;
    // ... more stuff ...
    case DONE:
        end_loop = true; break;
    }
}

Or even the following:

while ( msg->state != DONE ) {
    switch( msg->state ) {
    case MSGTYPE: // ... 
        break;
    // ... more stuff ...
}

5 Comments

Yeah, but I like exceptions even less ;-)
Using an exception to emulate a goto is of course worse than actually using a goto! It will probably also be significantly slower.
@Downvoter: It is because I state, that you shouldn't use exception, or because I suggest refactoring?
Not 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:"?
@Jonathan Leffler, Thanks, you showed the sample of valuable comment. updated the answer keeping in mind your comments.
5

There's no C++ construct for breaking out of the loop in this case.

Either use a flag to interrupt the loop or (if appropriate) extract your code into a function and use return.

Comments

5

No, C++ does not have a construct for this, given that the keyword "break" is already reserved for exiting the switch block. Alternatively a do..while() with an exit flag could suffice.

do { 
    switch(option){
        case 1: ..; break;
        ...
        case n: .. ;break;
        default: flag = false; break;
    }
} while(flag);

Comments

2

You could potentially use goto, but I would prefer to set a flag that stops the loop. Then break out of the switch.

1 Comment

Like, isnt a flag additional allocation. And checking of such flag additional cpu work. Plus you might want to do additional actions specific to the terminating condition. Now you seem to be in a mess of re checking all conditions. If you did this right at the event of the condition, you would already know what condition occured and write the specified action there.
2

Why not just fix the condition in your while loop, causing the problem to disappear?

while(msg->state != DONE)
{
    switch(msg->state) {
    case MSGTYPE: // ... 
        break;
    // ... more stuff ...
    case DONE:
        // We can't get here, but for completeness we list it.
        break; // **HERE, I want to break out of the loop itself**
    }
}

Comments

1

It amazes me how simple this is considering the depth of explanations... Here's all you need...

bool imLoopin = true;

while(imLoopin) {

    switch(msg->state) {

        case MSGTYPE: // ... 
            break;

        // ... more stuff ...

        case DONE:
            imLoopin = false;
            break;

    }

}

LOL!! Really! That's all you need! One extra variable!

2 Comments

for this specific example, sure. but the depth of explanations are warranted to answer the general question "How to break out of a loop from inside the switch"
Lol... well I was a different person twelve years ago my friend. 🙃
1

I think;

while(msg->state != mExit) 
{
    switch(msg->state) 
    {
      case MSGTYPE: // ...
         break;
      case DONE:
      //  .. 
      //  ..
      msg->state =mExit;
      break;
    }
}
if (msg->state ==mExit)
     msg->state =DONE;

Comments

1

I got same problem and solved using a flag.

bool flag = false;
while(true) {
    switch(msg->state) {
    case MSGTYPE: // ... 
        break;
    // ... more stuff ...
    case DONE:
        flag = true; // **HERE, I want to break out of the loop itself**
    }
    if(flag) break;
}

1 Comment

Neat! I was about to write the same answer.
1

Because the switch uses the break to break out from the switch (not from the while(1)), it needs the goto-statement:

while(1) {
    switch (*p) {
      case ' ':
        p++;
        break;
      case '\n':
        p++; *s=p; return(i);
      case '\0':
        *s=p; return(i);
      default:
        token[i]=p;
        i++;
        p++;
        goto ex1;
    };
  };
  ex1:

I can't add multiple case to same line like:

case ' ','\t':

it would be

case ' ': case '\t':

That's why maybe the break used here...

It looks the most frequent cases should be placed at the top of the list to make the program run faster. It may not have parallel execution for searching the different cases.

It is possible that the standard c then has missing some methods about this switching: https://blog.hackajob.co/better-c-switch-statements-for-a-range-of-values/ => allows you to use the <, >, <=, and >= operators in a switch expression

I was thinking that it should be (if c-language syntax changed) like:

switch (c) {
  case >= 5:
     ... op1
  endcase;
  case == 1:
  case == 3:
     ... op2
  endcase;
  default:
    ...
};

where op2 is executed when c is equal to 1 or 3 and when c is larger than or equal to 5 op1 is executed. Because comparison for equal or larger/smaller than would occur easily in similar manner.

  while(1) {
    switch (c) {
      case >= 2:
         ... op1
      case <= 5:
         ... op2
      break;
      default:
        ...
    };
  };

this case op1 is executed for c larger than 2 and op2 executed for 2<=c<=5 and break exits it from while-loop.

Comments

0

The simplest way to do it is to put a simple IF before you do the SWITCH , and that IF test your condition for exiting the loop .......... as simple as it can be

1 Comment

Um... you could be even simpler by putting that condition in the while argument. I mean that's what it's there for! :)
0

The break keyword in C++ only terminates the most-nested enclosing iteration or switch statement. Thus, you couldn't break out of the while (true) loop directly within the switch statement; however you could use the following code, which I think is an excellent pattern for this type of problem:

for (; msg->state != DONE; msg = next_message()) {
    switch (msg->state) {
    case MSGTYPE:
        //...
        break;

    //...
    }
}

If you needed to do something when msg->state equals DONE (such as run a cleanup routine), then place that code immediately after the for loop; i.e. if you currently have:

while (true) {
    switch (msg->state) {
    case MSGTYPE:
        //... 
        break;

    //...

    case DONE:
        do_cleanup();
        break;
    }

    if (msg->state == DONE)
        break;

    msg = next_message();
}

Then use instead:

for (; msg->state != DONE; msg = next_message()) {
    switch (msg->state) {
    case MSGTYPE:
        //...
        break;

    //...
    }
}

assert(msg->state == DONE);
do_cleanup();

Comments

0
while(MyCondition) {
switch(msg->state) {
case MSGTYPE: // ... 
    break;
// ... more stuff ...
case DONE:
   MyCondition=false; // just add this code and you will be out of loop.
    break; // **HERE, you want to break out of the loop itself**
}
}

Comments

0

Well its the crazy unruly homegrown cpp programmer with another one. The classy programmers have cringed against using terminating conditions inside loop body but I highly disagree. I qualify my belief with the fact that I used loops much more than the regular programmer, since I do text parsing manually and not with regex. Plus other kinds of situtations where I needed loops. So I understand the need for terminating conditions inside loops. Infact, even if I only have one condition, I may prefer a while(true) loop; in order to do all my code inside the loop body. eg:

while(true)
{
    if(condition)
    {
     // do something
     return;
    }

    // .... long body
}

This format allows persons to see what action is taken on loop termination immediately.

Anyhow, I will explain the BREAK_OUT_OF keyword. It allows you to break out of outer loops or switch statements, from within an inner loop or switch statement. This keyword is set to come in the next version of cpp, cpp 2026. But dont worry, for now you can emulate it in your primitive cpp compilers. Here are the steps.

Step 1: Download the BREAK_OUT_OF keyword package with the following command:

#define BREAK_OUT_OF(ID) goto STATEMENT##ID
#define S_ID(ID)
#define DEF_S_ID(ID) STATEMENT##ID:

Dont be fooled by the goto statement in the commands. Its not a regular goto statement that we all hate. Its a jmp statement in disguise.

Step 2: Now that you downloaded the compatibility package; when you need to break out of an outer statement from within an inner statement; you first give it an ID. You do this using S_ID keyword.

while(true) S_ID(first_loop)

Step 3: Place DEF_S_ID keyword immediately after statement body. Note that in the up coming cpp 26, This will automatically be done for us.

while(true) S_ID(first_loop)
{
}DEF_S_ID(first_loop)

Last Step: break out of outer loop from within inner loop using BREAK_OUT_OF keyword

while(true) S_ID(first_loop)
{
    switch(10) S_ID(1)
    {
     case 10: BREAK_OUT_OF(first_loop);
     case 0: BREAK_OUT_OF(1);
    }DEF_S_ID(1)
}DEF_S_ID(first_loop)

Comments

-2

If I remember C++ syntax well, you can add a label to break statements, just like for goto. So what you want would be easily written:

while(true) {
    switch(msg->state) {
    case MSGTYPE: // ...
        break;
    // ... more stuff ...
    case DONE:
        break outofloop; // **HERE, I want to break out of the loop itself**
    }
}

outofloop:
// rest of your code here

2 Comments

Unfortunately, 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.)
That must have been Java, then. Thanks for answering. And, of course, you're right with the rest, too.
-3
  while(true)
  {
    switch(x)
    {
     case 1:
     {
      break;
     }
    break;
   case 2:
    //some code here
   break;
  default:
  //some code here
  }
}

1 Comment

All the breaks in that code sample break out of the switch statement.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.