5

Here are the only two ways I know that roughly makes sense:

for (){
    for (){
        if (found the target) goto cont;
    }
}
cont:;

I've seen people strongly recommending against using goto, but I feel like this is a pretty proper way of using it.

bool exit=false;
for (){
    for (){
        if (found the target){
            exit=true;
            break;
        }
    }
    if (exit) break;
}

I write a bit more code this way.

What would you say to be the proper way to do this?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Michael Yang
  • 109
  • 1
  • 6

3 Answers3

3

You can add a layer of abstraction. If this is a loop that will be used in multiple places, then wrap it in a function like

auto do_stuff(params_t params)
{
    for (...){
        for (...){
            if (found_the_target) return something;
        }
    }
}

If this is a one off, then you can create a lambda on the fly like

auto thing_i_wanted_to_know = [&]{ for(...){ 
                                       for(...){ 
                                           if (found_the_target) return something; 
                                       }
                                   } 
                                 }();
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
1

Just change your nested loops the following way

bool exit=false;
for ( ; !exit; ){
    for ( ; !exit; ){
        if (found the target){
            exit=true;
        }
    }
}

Usually the inner for loop can be rewritten either like while or do-while loop avoiding using the break statement that makes the code more clear.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

I consider this to be a valid use of goto, but I myself use flags for this.


As an experiment, I've also ported Java's named loops to C++, using macros.

Usage:

for (int i = 0; i < 10; i++) LOOP_NAME(foo)
{
    for (int j = 0; j < 10; j++)
    {
        if (i == 5 && j == 5)
            break(foo);
    }
}

Implementation:

#define LOOP_NAME(name) \
    /* The variable in the conditions prevents `BREAK/CONTINUE` from */\
    /* being used outside of the loop with the matching name. */\
    if ([[maybe_unused]] constexpr bool _namedloop_InvalidBreakOrContinue = false) \
    { \
        [[maybe_unused]] LOOP_NAME_impl_cat(_namedloop_break_,name): break; \
        [[maybe_unused]] LOOP_NAME_impl_cat(_namedloop_continue_,name): continue; \
    } \
    else

#define LOOP_NAME_impl_cat(x, y) LOOP_NAME_impl_cat_(x, y)
#define LOOP_NAME_impl_cat_(x, y) x##y

#define BREAK(name) goto LOOP_NAME_impl_cat(_namedloop_break_,name)
#define CONTINUE(name) goto LOOP_NAME_impl_cat(_namedloop_continue_,name)

#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wkeyword-macro"
#endif
#define break(x) BREAK(x)
#define continue(x) CONTINUE(x)
#ifdef __clang__
#pragma clang diagnostic pop
#endif
HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207