Это плохая практика, чтобы использовать перерыв в цикле for? [закрытый]



это плохая практика, чтобы использовать break сообщении внутри for loop?



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



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



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



P. S: The руководство по кодированию Мисра советуют не использовать перерыв.

572   19  

19 ответов:

здесь много ответов, но я еще не видел этого:

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

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

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

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

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

используя break а также continue на for цикл прекрасно.

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

далеко от плохой практики, Python (и других языков?) продлил for цикл структура так часть его будет только выполняется, если цикл не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.')

общее правило: если следование правилу требует от вас сделать что-то более неудобное и трудное для чтения, а затем нарушить правило, затем нарушить правило.

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

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?

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

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

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;
}

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

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

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

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

for element in bigList: ...

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

нет ничего изначально неправильного в использовании инструкции 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) часто увеличиваются цикломатическая сложность что затрудняет доказательство того, что код делает правильную вещь во всех случаях.

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

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

не похоже, что они были в одной лиге с перейти. :)

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

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

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

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

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

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

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

  • у них есть структура разработки, которая поощряет определенный стиль программирования / кода, и у них есть статистические данные о том, что это дает чистую выгоду в этой ограниченной структуре, или
  • на них повлияли рекомендации по программированию или опыт работы в таких рамках, или
  • они просто диктаторские идиоты, или
  • любой из вышеприведенная + историческая инерция (уместная в том, что обоснования более применимы к C, чем современный C++).

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

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

Я не вижу причин, почему это было бы плохой практикой при условии, что вы хотите завершить остановку обработки в этот момент.

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

    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;

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

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

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

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

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

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

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

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

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

я тоже искал continue заявления. Найти ни одной.

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

Edit: перерыв разрешен в MISRA ' 04

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

Почему вы игнорируете встроенную функциональность цикла 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]);
}

"профессиональный код", который пронизан перерывами, на самом деле не звучит как профессиональный код для меня. Это звучит как ленивое кодирование ;)

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

Comments

    Ничего не найдено.