Search code examples
c++closurestry-catchgoto

Alternitives to C like labling and escaping nested loops for C++


In C and in javascript I enjoy the ability to write this kind of thing and have it just work.

while (a)
{
ctx: while(b)
     {
         while (c)
         {
             if(d) break ctx;
             ...
         }
     }
     ...
}

Perhaps I'm just confused about C++ versions but I get this kind of error in g++:

error: expected ‘;’ before ‘ctx’
     break ctx;
error: ‘ctx’ was not declared in this scope
warning: label ‘ctx’ defined but not used [-Wunused-label]
 ctx:

C++ appears to refuse letting me write this code. C++ has added lambdas/closures that potentially would let me do this but I'm not quite sure how they would work in this case.

Using try throw catch is the closest construct I can think of that produces this behavior but the sloppiness of using an error system when none should be needed concerns me (Also they are slow I hear).

I'm tempted to just wrap it in extern C except I'm relying on c++ library's completely for the entire project so this also feels sloppy.

Is a try block or just rewriting my only options?


Solution

  • Neither C nor C++ have a labelled break statement (You're probably using a language extension, rather than standard C).

    Instead, you can use goto to break out of a nested loop.

    while (a)
    {
        while(b)
        {
            while (c)
            {
                if(d)
                    goto break_b;
            }
        }
        break_b:
        // ...
    }
    

    I was able to use goto to solve this... I though it was a banned construct in c++?

    No. goto is not "banned" in C++.

    This is a completely fine way to use goto. There doesn't exist an equivalent structured control statement.


    lambdas/closures [...] potentially would let me do this but I'm not quite sure how they would work in this case.

    If you are allergic to goto, then you can indeed use a lambda, but I don't see it providing any additional readability:

    while (a)
    {
        [&](){
            while(b)
            {
                while (c)
                {
                    if(d)
                        return;
                }
            }
        }();
        // ...
    }
    

    Instead of a lambda, you can use a named function. But in that case you need to pass any variables (such as b, c and d) as arguments (assuming they're not globals).


    Yet another way is an extra variable:

    while (a)
    {
        bool break_b = false;
        while(b)
        {
            while (c)
            {
                if(d) {
                    break_b = true;
                    break;
                }
            }
            if (break_b)
                break;
        }
        // ...
    }
    

    Of these three methods, I recommend goto, since it's the most readable. Except in the case the actual inner loop omitted from the example is very long, in which case a separate function might be better.