Условия завершения цикла - PullRequest
       48

Условия завершения цикла

5 голосов
/ 25 сентября 2008

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

1   for ( int i = 0; i != N; ++i )

2   for ( int i = 0; i < N; ++i )

Разница становится понятной в постусловиях:

  • Первый дает сильную гарантию, что i == N после завершения цикла.

  • Второй дает слабую гарантию того, что i >= N после завершения цикла, но у вас возникнет соблазн предположить, что i == N.

Если по какой-либо причине приращение ++i когда-либо изменяется на что-то вроде i += 2, или если i изменяется внутри цикла, или если N отрицательно, программа может завершиться ошибкой:

  • Первый может застрять в бесконечном цикле. Сбой рано, в цикле с ошибкой. Отладка проста.

  • Второй цикл завершится, и через некоторое время программа может завершиться с ошибкой из-за вашего неверного предположения i == N. Он может потерпеть неудачу вдали от цикла, вызвавшего ошибку, что затрудняет его отслеживание. Или он может молча продолжать делать что-то неожиданное, что еще хуже.

Какое условие прекращения вы предпочитаете и почему? Есть ли другие соображения? Почему многие программисты, которые знают это, отказываются применять это?

Ответы [ 13 ]

0 голосов
/ 25 сентября 2008

Я думаю, вы очень хорошо изложили разницу между ними. У меня есть следующие комментарии, хотя:

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

  • Вы объявили i индекс в пределах for, поэтому я бы не стал делать ставку на значение i после цикла. Примеры немного вводят в заблуждение, поскольку подразумевают, что for определенный цикл. На самом деле это просто более удобный способ записи:

    // version 1
    { int i = 0;
      while (i != N) {
        ...
        ++i;
      }
    }
    

    Обратите внимание, что i не определено после блока.

Если программист знал, что все вышеперечисленное не будет делать общее предположение о значении i и будет достаточно мудро выбрать i<N в качестве конечных условий, чтобы гарантировать, что условие выхода будет в конечном итоге выполнено.

0 голосов
/ 25 сентября 2008

Я предпочитаю использовать # 2 только потому, что стараюсь не расширять значение i вне цикла for. Если бы я отслеживал такую ​​переменную, я бы создал дополнительный тест. Некоторые могут сказать, что это избыточно или неэффективно, но это напоминает читателю о моих намерениях: В этот момент я должен равняться N

@ timyates - я согласен, что не стоит полагаться на побочные эффекты

0 голосов
/ 25 сентября 2008

В общем, я бы предпочел

for ( int i = 0; i < N; ++i )

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...