开发者

C++: break the main loop

I am preparing some code:

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

I want to break the main loop 开发者_运维知识库(loop variable int a) by using a break; statement in the b loop (loop variable int b).

How can I do it?


Use a 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:


Either do one of four things: use goto, use throw, use a flag, or refactor.

Many will disagree with using goto, but sometimes it's a clean solution. (Most times, it isn't, but it exists for a reason.) However, I find the use of goto warrants a refactor.

The second solution is to throw some special exception and then catch it just outside the main loop. This is an abuse of the exception system and basically a worse goto; use a goto instead of this.

The third solution would be to use a flag of some sort. This is basically a "safer" goto, but some might argue it's a bit uglier. (Especially with multiple-levels. Though in such a case your concern is how ugly your code is.)

The solution I would recommend is refactor. Whatever you're doing, it's too much. You should move the inner loops into a function, and call that function. Returning to the main loop is simply a return from that function. (In other words "My work is done.")


I recommend refactoring your code into a function. Then you can just return from that function instead of using 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
        }

        .
        .
        .
    }
}

This - or perhaps even a more involved refactoring of your code - should lend itself to a clean, elegant solution. Alternatively, if you just want a quick fix you could use a condition variable:

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;

    .
    .
    .
}

Others have suggested using goto. While that is another quick fix, I strongly recommend against it, especially if you are working in a rigorous environment where the code will be peer reviewed and used for years down the road.

In my opinion the goto approach is a bit harder to maintain than a function/return refactoring, especially later on when someone else makes changes to the code. Plus you will have to justify the goto to anyone else on the team that happens to stumble onto the code.


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:


If it is appropriate, you could make a function who's contents are the a loop, and 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


The only way to head out of two such loops at a time is a goto or a throw or a return, and throw and return may not be appropriate (particularly throw, if the condition isn't exceptional). Alternately, you could set some sort of condition (bool breakout;), and keep breaking if it's true.


\ (◕ ◡ ◕) /

[]() {
    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
        {
           .
           .
           .
        }
    }
}();


  1. Use a 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. set a sentinel value tested by each loop:

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


One simple strategy is to put the loop in a separate function and do a return at the selected point:

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

Any kind of result may also be returned with a return value, or with a reference parameter for the function.


The ideal way would be to re-factor your code so that you no longer need such a complicated nested-loop structure. Depending on what the rest of your code looks like, your b and c loops may be candidates for becoming individual functions, if not the entire a loop.

Since it looks like loops b and c iterate over adjacent ranges, why not combine them and reduce your loop nesting a bit?

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:

You can also use a condition variable instead of the goto. If you want to break out of the old b loop but still process the old c loop, simply set count = 2001 inside the old b loop code.

Ideally, you would at least be able to re-factor this to something more like

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

where the function process_inner_loop wraps up your original two loops and returns non-zero if you want to break out of the enclosing loop. Now, instead of using goto or condition variables, you can simply return 1;.


Use this kind of pattern

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++)
    {
       .
       .
       .
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜