在C++中有更好的方法来退出嵌套的for循环吗?

5

以下是我所知的大致可行的两种方式:

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

我看到很多人强烈反对使用 goto,但我认为这是一个相当合适的使用方式。

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

我以这种方式写了更多的代码。

你认为应该如何正确地完成这个任务?


4
将循环或循环嵌套放入函数或lambda中,并使用return语句,而非gotobreak - Eljay
2
为了跳出嵌套循环,使用goto被认为是合适的。请参阅这个最受欢迎的答案获取更多信息。 - Andreas Wenzel
4
这是一个明确的信号,内部循环应该在单独的函数中。 - john
1
你也可以使用异常,但要注意抛出异常的代价。 - Goswin von Brederlow
1
@GoswinvonBrederlow,你不应该这样做,因为代价太高了。而且任何需要调试你的程序的人都会讨厌你。 - HolyBlackCat
显示剩余5条评论
3个回答

3
你可以添加一层抽象。如果这是一个将在多个地方使用的循环,则可以像下面这样将其包装在一个函数中:
auto do_stuff(params_t params)
{
    for (...){
        for (...){
            if (found_the_target) return something;
        }
    }
}

如果这是一次性的需求,那么您可以即时创建一个 Lambda 函数,例如:
auto thing_i_wanted_to_know = [&]{ for(...){ 
                                       for(...){ 
                                           if (found_the_target) return something; 
                                       }
                                   } 
                                 }();

1

只需按照以下方式更改嵌套循环即可。

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

通常内层的for循环可以被重写为while或do-while循环,避免使用break语句以使代码更清晰。


0

我认为这是使用 goto 的有效方法,但我自己会使用标志来实现。


作为一个实验,我也将Java的命名循环使用宏移植到了C++中。
用法:
for (int i = 0; i < 10; i++) LOOP_NAME(foo)
{
    for (int j = 0; j < 10; j++)
    {
        if (i == 5 && j == 5)
            break(foo);
    }
}

实现

#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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接