C++: разорвать основной цикл

Я готовлю код:

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

Я хочу разорвать основной цикл (переменная цикла int a) С помощью break; оператор в цикле b (переменная цикла int b).

как я могу это сделать?

11 ответов


Я рекомендую рефакторинг кода в функцию. Тогда вы можете просто return из этой функции, вместо использования 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
        }

        .
        .
        .
    }
}

это - или, возможно, даже более сложный рефакторинг вашего кода - должно поддаваться чистому, элегантному решению. Кроме того, если вы просто хотите быстро исправить, вы можете использовать переменную условия:

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;

    .
    .
    .
}

другие предложили использовать goto. Хотя это еще одно быстрое исправление, я настоятельно рекомендую против него, особенно, если вы работаете в строгой среде, где код будет рецензироваться и использоваться в течение многих лет.

на мое мнение the goto подход немного сложнее поддерживать, чем рефакторинг функции/возврата, особенно позже, когда кто-то другой вносит изменения в код. Плюс вам придется оправдать goto для всех остальных членов команды, которые случайно наткнулись на код.


использовать 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:

либо сделайте одну из четырех вещей: используйте goto используйте throw, используйте флаг или рефакторинг.

многие не согласятся с используя goto, а иногда это чистое решение. (В большинстве случаев это не так, но оно существует по какой-то причине.) Тем не менее, я нахожу использование goto требует рефакторинга.

второй вариант бросить некоторые специальные исключения, а затем поймать его только вне основного цикла. Это злоупотребление система исключений и в основном хуже goto; использовать goto вместо этого.

третьим решением было бы использовать флаг of какой-то. Это в основном "безопаснее"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 end;
    }

    for(int c = 2001; c <= 3000; c++)    //loop c
    {
       .
       .
       .
    }
}
end:

если это уместно, вы можете сделать функцию, содержимое которой является циклом a, и использовать 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

единственный способ выйти из двух таких петель за раз-это goto или throw или return и throw и return может быть не подходит (особенно throw, если условие не является исключительным). В качестве альтернативы вы можете установить какое-то условие (bool breakout;), и продолжайте ломать, если это правда.


\ (◡ ◕ ◕) /

[]() {
    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. использовать 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. установите значение sentinel, проверенное каждым циклом:

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

одна простая стратегия-поместить цикл в отдельную функцию и сделать возврат в выбранной точке:

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

любой результат может быть возвращен с возвращаемым значением или со значением параметра ссылку на функцию.


идеальным способом было бы повторно-фактор ваш код, так что вам больше не нужна столь сложная вложенного цикла структуры. В зависимости от того, как выглядит остальная часть вашего кода, ваш b и c петли могут быть кандидатами на то, чтобы стать отдельными функциями, если не все a петли.

так как это выглядит как петли b и c итерация по смежным диапазонам, почему бы не объединить их и немного уменьшить вложенность цикла?

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:

вы также можете использовать переменная условия вместо goto. Если вы хотите вырваться из старого b цикл, но все еще обрабатывать старый c loop, просто установите count = 2001 внутри старого b код цикла.

в идеале, вы, по крайней мере, сможете перефразировать это на что-то вроде

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

где функция process_inner_loop обертывает исходные два цикла и возвращает ненулевое значение, если вы хотите вырваться из замкнутого цикла. Теперь вместо использования goto или условие переменные, вы можете просто return 1;.


используйте такой шаблон

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