Плохо ли использовать разрыв в цикле for? [закрыто]

Является ли плохой практикой использование break внутри for loop ?

Скажем, я ищу значение в массиве. Сравните внутри цикла for, и когда значение будет найдено, break;, чтобы выйти из цикла for.

Это плохая практика? Я видел используемую альтернативу: определите переменную vFound и установите для нее значение true, когда значение будет найдено, и проверьте vFound в условии оператора for. Но нужно ли создавать новую переменную только для этой цели?

Я спрашиваю в контексте обычного цикла C или C ++ для цикла.

P.S: Рекомендации по кодированию MISRA не рекомендуют использовать разрыв.

109 голосов | спросил kiki 13 +04002010-10-13T14:14:43+04:00312010bEurope/MoscowWed, 13 Oct 2010 14:14:43 +0400 2010, 14:14:43

19 ответов


0

Здесь много ответов, но я еще не видел упомянутое:

Большинство «опасностей» связано с использованием break или continue в цикле for отменяется, если вы пишете аккуратные, легко читаемые циклы. Если тело вашего цикла занимает несколько экранов и имеет несколько вложенных подблоков, да, вы можете легко забыть, что некоторый код не будет выполнен после разрыва. Однако, если цикл короткий и конкретный, цель оператора break должна быть очевидна.

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

ответил e.James 13 +04002010-10-13T21:16:54+04:00312010bEurope/MoscowWed, 13 Oct 2010 21:16:54 +0400 2010, 21:16:54
0

Нет, перерыв - правильное решение.

Добавление логической переменной затрудняет чтение кода и добавляет потенциальный источник ошибок.

ответил smirkingman 13 +04002010-10-13T14:27:30+04:00312010bEurope/MoscowWed, 13 Oct 2010 14:27:30 +0400 2010, 14:27:30
0

Вы можете найти все виды профессионального кода с операторами «break» в них. Это имеет смысл использовать это всякий раз, когда это необходимо. В вашем случае эта опция лучше, чем создание отдельной переменной только для выхода из цикла.

ответил Amit S 13 +04002010-10-13T14:40:21+04:00312010bEurope/MoscowWed, 13 Oct 2010 14:40:21 +0400 2010, 14:40:21
0

Использование break, а также continue в цикле for отлично.

Это упрощает код и улучшает его читаемость.

ответил 13 +04002010-10-13T14:18:06+04:00312010bEurope/MoscowWed, 13 Oct 2010 14:18:06 +0400 2010, 14:18:06
0

Совсем не плохая практика, Python (и другие языки?) расширил структура статей" rel =" nofollow noreferrer "> for loop , поэтому часть ее будет только выполняется, если цикл не break.

for n in range(5):
    for m in range(3):
        if m >= n:
            print('stop!')
            break
        print(m, end=' ')
    else:
        print('finished.')

Вывод:

stop!
0 stop!
0 1 stop!
0 1 2 finished.
0 1 2 finished.

Эквивалентный код без break и этого удобного else

for n in range(5):
    aborted = False
    for m in range(3):
        if not aborted:
            if m >= n:
                print('stop!')
                aborted = True
            else:            
                print(m, end=' ')
    if not aborted:
        print('finished.')
ответил Nick T 13 +04002010-10-13T17:54:02+04:00312010bEurope/MoscowWed, 13 Oct 2010 17:54:02 +0400 2010, 17:54:02
0

Общее правило. Если следование правилу требует от вас выполнения чего-то более неуклюжего и трудного для чтения, то нарушайте правило, а затем нарушайте правило.

В случае зацикливания, пока вы не найдете что-то, вы сталкиваетесь с проблемой различения найденного и не найденного при выходе. То есть:

for (int x=0;x<fooCount;++x)
{
  Foo foo=getFooSomehow(x);
  if (foo.bar==42)
    break;
}
// So when we get here, did we find one, or did we fall out the bottom?

Итак, вы можете установить флаг или инициализировать "найденное" значение равным нулю. Но

Вот почему в целом я предпочитаю вставлять свои поиски в функции:

Foo findFoo(int wantBar)
{
  for (int x=0;x<fooCount;++x)
  {
    Foo foo=getFooSomehow(x);
    if (foo.bar==wantBar)
      return foo;
  }
  // Not found
  return null;
}

Это также помогает загромождать код. В основной строке «find» становится отдельным оператором, а когда условия являются сложными, они записываются только один раз.

ответил Jay 13 +04002010-10-13T18:33:00+04:00312010bEurope/MoscowWed, 13 Oct 2010 18:33:00 +0400 2010, 18:33:00
0

break - это вполне допустимое утверждение (как и continue , кстати). Все дело в читабельности кода - если у вас нет слишком сложных циклов и тому подобного, это нормально.

Не то чтобы они были в одной лиге с goto . :)

ответил riviera 13 +04002010-10-13T15:09:34+04:00312010bEurope/MoscowWed, 13 Oct 2010 15:09:34 +0400 2010, 15:09:34
0

Это зависит от языка. Хотя вы можете проверить логическую переменную здесь:

for (int i = 0; i < 100 && stayInLoop; i++) { ... }

это невозможно сделать при переходе по массиву:

for element in bigList: ...

В любом случае, break сделает оба кода более читабельными.

ответил eumiro 13 +04002010-10-13T14:21:18+04:00312010bEurope/MoscowWed, 13 Oct 2010 14:21:18 +0400 2010, 14:21:18
0

Нет ничего плохого в использовании оператора break, но вложенные циклы могут привести к путанице. Чтобы улучшить читаемость, многие языки ( по крайней мере Java поддерживает ) поддерживают взлом на ярлыки, которые значительно улучшат читабельность.

int[] iArray = new int[]{0,1,2,3,4,5,6,7,8,9};
int[] jArray = new int[]{0,1,2,3,4,5,6,7,8,9};

// label for i loop
iLoop: for (int i = 0; i < iArray.length; i++) {

    // label for j loop
    jLoop: for (int j = 0; j < jArray.length; j++) {

        if(iArray[i] < jArray[j]){
            // break i and j loops
            break iLoop;
        } else if (iArray[i] > jArray[j]){  
            // breaks only j loop
            break jLoop;
        } else {
            // unclear which loop is ending
            // (breaks only the j loop)
            break;
        }
    }
}

Я скажу, что операторы break (и return) часто увеличивают цикломатическую сложность , что усложняет ее Доказать, что код делает правильную вещь во всех случаях.

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

ответил cyber-monk 13 +04002010-10-13T20:24:35+04:00312010bEurope/MoscowWed, 13 Oct 2010 20:24:35 +0400 2010, 20:24:35
0

В вашем примере вы не знаете количество итераций для цикла for . Почему бы не использовать цикл while вместо этого, что позволяет количеству итераций быть неопределенными в начале?

Следовательно, в общем случае нет необходимости использовать breakmemement , так как цикл лучше описать как цикл while .

ответил Schedler 13 +04002010-10-13T14:21:44+04:00312010bEurope/MoscowWed, 13 Oct 2010 14:21:44 +0400 2010, 14:21:44
0

Я согласен с другими, которые рекомендуют использовать break. Очевидный вытекающий из этого вопрос: зачем кому-то рекомендовать иначе? Хорошо ... когда вы используете break, вы пропускаете оставшуюся часть кода в блоке и оставшиеся итерации. Иногда это приводит к ошибкам, например:

  • ресурс, полученный в верхней части блока, может быть освобожден в нижней части (это верно даже для блоков внутри for зацикливается), но этот шаг выпуска может быть случайно пропущен, когда «преждевременный» выход вызван оператором break (в «modern») C ++, «RAII» используется для того, чтобы обрабатывать это надежным и безопасным для исключений способом: в основном, деструкторы объекта надежно освобождают ресурсы независимо от того, как выходит область действия)

  • кто-то может изменить условный тест в операторе for, не заметив, что существуют другие делокализованные условия выхода

  • Ответ ndim отмечает, что некоторые люди могут избегать использования break, чтобы поддерживать относительно согласованное время выполнения цикла, но вы были сравнение break с использованием логической переменной управления с ранним выходом, где она не хранится

Время от времени люди, наблюдающие такие ошибки, понимают, что они могут быть предотвращены /смягчены этим правилом «без разрывов» ... действительно, существует целая стратегия для «более безопасного» программирования, называемая «структурированным программированием», где каждая функция должен иметь одну точку входа и выхода (т.е. нет возврата, нет раннего возврата). Это может устранить некоторые ошибки, но, несомненно, вводит другие. Почему они это делают?

  • у них есть структура разработки, которая поощряет определенный стиль программирования /кода, и у них есть статистические доказательства того, что это дает чистую выгоду в этой ограниченной структуре, или
  • на них повлияли рекомендации по программированию или опыт работы в такой среде, или
  • они просто идиоты-диктаторы, или
  • любая из вышеперечисленных + историческая инерция (уместно в том смысле, что обоснования более применимы к C, чем к современному C ++).
ответил Tony Delroy 13 +04002010-10-13T15:57:27+04:00312010bEurope/MoscowWed, 13 Oct 2010 15:57:27 +0400 2010, 15:57:27
0

Совершенно верно использовать break - как уже отмечали другие, он нигде не находится в той же лиге, что и goto.

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

ответил Ace 13 +04002010-10-13T16:53:13+04:00312010bEurope/MoscowWed, 13 Oct 2010 16:53:13 +0400 2010, 16:53:13
0

Я не вижу причин, по которым было бы плохой практикой. ПРЕДОСТАВЛЯЕТСЯ, что вы хотите завершить обработку STOP в этот момент.

ответил Cornelius J. van Dyk 13 +04002010-10-13T20:21:35+04:00312010bEurope/MoscowWed, 13 Oct 2010 20:21:35 +0400 2010, 20:21:35
0

Во встроенном мире существует множество кода, который использует следующую конструкцию:

    while(1)
    { 
         if (RCIF)
           gx();
         if (command_received == command_we_are_waiting_on)
           break;
         else if ((num_attempts > MAX_ATTEMPTS) || (TickGet() - BaseTick > MAX_TIMEOUT))
           return ERROR;
         num_attempts++;
    }
    if (call_some_bool_returning_function())
      return TRUE;
    else
      return FALSE;

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

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

ответил Nate 13 +04002010-10-13T18:11:23+04:00312010bEurope/MoscowWed, 13 Oct 2010 18:11:23 +0400 2010, 18:11:23
0

Зависит от вашего варианта использования. Существуют приложения, в которых время выполнения цикла for должно быть постоянным (например, чтобы удовлетворить некоторые ограничения синхронизации или скрыть внутренние данные от атак на основе синхронизации).

В этих случаях имеет смысл установить флаг и проверять только значение флага ПОСЛЕ того, как все итерации цикла for запустить. Конечно, все итерации цикла for должны запускать код, который все еще занимает примерно одно и то же время.

Если вас не волнует время выполнения ... используйте break; и continue; для облегчения чтения кода.

ответил ndim 13 +04002010-10-13T15:02:17+04:00312010bEurope/MoscowWed, 13 Oct 2010 15:02:17 +0400 2010, 15:02:17
0

Я провел некоторый анализ кодовой базы, над которой я сейчас работаю (40 000 строк JavaScript).

Я нашел только 22 break, из них:

  • 19 были использованы внутри операторов switch (всего у нас всего 3 оператора switch!).
  • 2 были использованы внутри циклов for - код, который я сразу классифицировал, чтобы он был преобразован в отдельные функции и заменен на return заявление.
  • Что касается окончательного break внутри while

Итак, согласно моей статистике: Если break используется за пределами switch, это запах кода.

Я также искал continue. Не найдено ни одного.

ответил Rene Saarsoo 13 +04002010-10-13T21:21:24+04:00312010bEurope/MoscowWed, 13 Oct 2010 21:21:24 +0400 2010, 21:21:24
0

В соответствии с MISRA 98 правилами, которые используются в моей компании в C dev, оператор break должен не будет использоваться ...

Изменить: Разрыв разрешен в MISRA '04

ответил Benoît 13 +04002010-10-13T15:05:27+04:00312010bEurope/MoscowWed, 13 Oct 2010 15:05:27 +0400 2010, 15:05:27
0

Я не согласен!

Почему вы игнорируете встроенную функциональность цикла for, чтобы создавать свои собственные? Вам не нужно изобретать велосипед.

Я думаю, что имеет больше смысла, чтобы ваши чеки были в верхней части цикла for, например, так

for(int i = 0; i < myCollection.Length && myCollection[i].SomeValue != "Break Condition"; i++)
{
//loop body
}

или если вам нужно сначала обработать строку

for(int i = 0; i < myCollection.Length && (i == 0 ? true : myCollection[i-1].SomeValue != "Break Condition"); i++)
{
//loop body
}

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

for(int i = 0; i < myCollection.Length && (i == 0 ? true : myCollection[i-1].SomeValue != "Break Condition"); i++)
{
    DoAllThatCrazyStuff(myCollection[i]);
}

Или, если ваше состояние сложное, вы также можете удалить этот код!

for(int i = 0; i < myCollection.Length && BreakFunctionCheck(i, myCollection); i++)
{
    DoAllThatCrazyStuff(myCollection[i]);
}

«Профессиональный код», изобилующий перерывами, на самом деле не похож на профессиональный код. Звучит как ленивое кодирование;)

ответил Biff MaGriff 13 +04002010-10-13T20:22:13+04:00312010bEurope/MoscowWed, 13 Oct 2010 20:22:13 +0400 2010, 20:22:13
0

Конечно, break; - это решение для остановки цикла for или цикла foreach. Я использовал его в php в foreach и для цикла и нашел работу.

ответил gautamlakum 13 +04002010-10-13T15:01:05+04:00312010bEurope/MoscowWed, 13 Oct 2010 15:01:05 +0400 2010, 15:01:05

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132