Бесконечные петли в плохой форме? - PullRequest
7 голосов
/ 03 июня 2009

Итак, у меня есть код C ++ для узлов обратного отслеживания в алгоритме BFS. Это выглядит примерно так:

typedef std::map<int> MapType;
bool IsValuePresent(const MapType& myMap, int beginVal, int searchVal)
{
    int current_val = beginVal;
    while (true)
    {
        if (current_val == searchVal)
            return true;

        MapType::iterator it = myMap.find(current_val);
        assert(current_val != myMap.end());
        if (current_val == it->second) // end of the line
            return false;
        current_val = it->second;
    }
}

Однако, while (true) кажется ... мне подозрительным. Я знаю, что этот код работает, и логически я знаю, что он должен работать. Однако я не могу избавиться от ощущения, что в while должно быть какое-то условие, но на самом деле единственно возможное - это использовать переменную bool, просто чтобы сказать, выполнено ли это. Должен ли я перестать беспокоиться? Или это действительно плохая форма.

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

Ответы [ 12 ]

22 голосов
/ 03 июня 2009

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

while (current_val != searchVal ) {
    MapType::iterator it = myMap.find(current_val);
    assert(current_val != myMap.end());
    if (current_val == it->second) // end of the line
        return false;
    current_val = it->second
}
return true;

Это, кажется, лучше отражает истинное намерение цикла

13 голосов
/ 03 июня 2009

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

while(true)

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

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

while (currentVal != searchVal)

работает, поэтому while (true) явно уступает, и в этом случае его следует избегать.

6 голосов
/ 03 июня 2009

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

while (currentVal != searchVal)
{
    ...
}
return true;

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

5 голосов
/ 03 июня 2009

Я согласен с другими ответами, что в этом случае нет необходимости в бесконечном цикле.

Однако другой момент может заключаться в том, что, когда у вас do есть бесконечный цикл, for(;;) может быть лучшим способом выразить это. Некоторые компиляторы генерируют предупреждения для while(true) (условие всегда оценивается как ложное), и ваше намерение менее ясно, поскольку оно похоже на любой другой цикл. Возможно, раньше говорилось while (x == true), и вы случайно удалили x вместо true. for(;;) довольно ясно говорит, что это должен быть бесконечный цикл. Или, возможно, вы намеревались написать что-то вроде while(t), но Intellisense в вашей IDE включился и решил автозаполнить до true.

for(;;) с другой стороны, это не то, что вы бы случайно набрали. (и его проще искать. while (true) также можно записать как while (1))

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

5 голосов
/ 03 июня 2009

Бывают ситуации, когда такая конструкция имеет смысл:

  1. Условие разрыва вычисляется в цикле
  2. Есть больше разрушающих условий, и все они одинаково важны
  3. Вы действительно хотите бесконечный цикл;) ..
4 голосов
/ 03 июня 2009

while(true) используется в играх для основного игрового цикла - игры непрерывно читают входные данные игрока, обрабатывают взаимодействия между объектами и рисуют экран, а затем повторяют. Этот цикл продолжается бесконечно, пока из этого цикла не выйдет какое-то другое действие (выход из игры, завершение уровня).

Я попытался быстро найти этот основной цикл в исходном коде Quake 1 для вас, но было по крайней мере 50 вхождений 'while(1)', а также несколько написанных как 'for(;;)', и я не был Я сразу понял, какой из них был основным игровым циклом.

1 голос
/ 03 июня 2009

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

Я не очень боюсь их или чего-то еще, но я знаю, что некоторые люди.

0 голосов
/ 01 сентября 2009

Я люблю бесконечные циклы как внешнюю управляющую структуру конечного автомата. Это фактически структурированный переход:

for (;;) {
    int c = ReadInput();
    if (c == EOF)
        return kEOF;

    switch (state) {
    case inNumber: state = HandleNumber(c); break;
    case inToken: state = HandleToken(c); break;
    case inWhiteSpace: state = HandleWhiteSpace(c);
    default:
       state = inError;
       break;
    }
    if (state == inError) ThrowError();

}

0 голосов
/ 03 июня 2009

Нередко в коде встроенных систем можно найти бесконечные циклы - часто окружающие конечные автоматы, проверяющие периферийные чипы и устройства и т. Д.

0 голосов
/ 03 июня 2009

Ну, да , но две страницы кода, которые вы должны написать, если вы не хотите, чтобы ваш основной цикл был похож на while(true), это даже хуже форма.

...