2009-06-02 7 views
7

Итак, у меня есть код 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: Спасибо всем, что заметили, что есть способ обойти это. Тем не менее, мне все равно хотелось бы узнать, существуют ли другие действительные случаи.

+0

Это также обсуждалось немного здесь. http://stackoverflow.com/questions/885908/ – Copas

+0

Я не знаю. Бесконечные петли в плохом состоянии? –

ответ

22

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

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; 

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

+5

+1 Для более четкого выражения намерения и функции. –

+0

, вы все равно можете улучшить инициализацию current_val до map.begin() и добавить к условию while (... && current_val! = It-> second) и, возможно, даже преобразовать в do-while – stefanB

+0

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

0

Ну, комментарий о том, что это на самом деле не бесконечный цикл поможет:

while (true) // Not really an infinite loop! Guaranteed to return. 

Я согласен, что он должен иметь состояние, но это нормально в некоторых ситуациях (и это не всегда возможно или легко сделать условие).

+0

Если ссылки каким-то образом получают бродячую ссылку на что-то рядом с началом цепочки, то она будет зацикливаться навсегда. Это верно как для версии «бесконечного цикла», так и для версии, разработанной JaredPar. Тем не менее, его версия на самом деле показывает намерения контуров в условном, где у вас нет – DevinB

+0

Да! Комментарии всегда решают эту проблему. –

+0

Это довольно бесполезный комментарий. Он не говорит, при каких условиях он возвращается, ничего. Хороший комментарий может заключаться в том, что он возвращается под особым набором условий, которые слишком сложны, чтобы вкратце вписаться в эту пару круглых скобок, а затем перечислить условия. Конечно, если бы вы четко прокомментировали это, вы могли бы также КОДА, что ясно в первом случае (как правило, это так) –

6

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

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

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

+0

Что делать, если я хочу заставить демона уйти? – 2009-06-03 00:04:43

+0

У вас есть выбор - либо выйти из неопределенного цикла, либо вызвать функцию выхода, которая не возвращается. Оба они эффективны. –

+0

Полагаю, я должен сказать: «либо перерыв (или возврат) из ...» –

5

Есть ситуации, когда конструкция, как это имеет смысл:

  1. Условие перерыва вычисляется внутри цикла
  2. Есть более переломные условия, и все они одинаково важны
  3. Вы действительно хотите, бесконечная петля;).
0

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

+0

Как показал JaredPar, это не упрощает логику. Как я уже сказал, документальное подтверждение это, безусловно, хорошая идея. – Zifre

0

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

1

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

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

13

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

while(true) 

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

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

while (currentVal != searchVal) 

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

4

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

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

+0

Интересно, действительно ли это хороший пример того, почему НЕ использовать while (true) ... Я имею в виду, что если вы использовали его только в тех случаях, которые не возвращаются, вы бы знали, какой из них был игровым циклом. Еще лучше, если кто-то сказал (работает), вы бы знали, какой из них был реальным циклом, и вы будете общаться с программистом точно, как вы ожидаете, что его остановят (в противном случае это перерыв? Return? Exit? какой из них приведет к правильной процедуре завершения?) –

+0

Большинство игровых петель, которые я видел или писал, больше похожи на 'while (! Exiting) {...}' – Zifre

+0

'while (running)', вероятно, было бы замечено как отходы циклов ЦП - проверка переменной 'running' будет отнимать цикл или два, и даже больше будет потрачено впустую, ожидая, что она будет считана из ОЗУ. –

5

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

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

for(;;) С другой стороны, это не то, что вы когда-либо случайно вводили. (И это легче искать. В то время (правда), также может быть записана как в то время как (1))

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

+0

+1 для объяснения разницы между 'for (;;)' и 'while (true)' – pierrotlefou

0

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

0

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

}

+0

Это все равно должно выглядеть как 'while ((int c = ReadInput())! = EOF) {..}' – Erbureth

+0

силы c выходят за рамки цикла или вы не можете различать EOF и ошибку. Стройные конструкции контура не всегда являются вашим другом. – plinth

Смежные вопросы