2009-06-02 18 views
7

Así que tengo un código C++ para los nodos de seguimiento en un algoritmo BFS. Se ve un poco como esto:¿Hay bucles sin fin en mal estado?

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

Sin embargo, el while (true) parece sospechoso ... a mí. Sé que este código funciona, y lógicamente sé que debería funcionar. Sin embargo, no puedo evitar la sensación de que debería haber alguna condición en el while, pero realmente la única posible es usar una variable bool solo para decir si está lista. ¿Debería dejar de preocuparme? O es esta realmente mala forma.

EDIT: Gracias a todos por notar que hay una forma de evitar esto. Sin embargo, me gustaría saber si hay otros casos válidos.

+0

Esto también se discutió un poco aquí. http://stackoverflow.com/questions/885908/ – Copas

+0

No lo sé. Son bucles sin fin en mal estado? –

Respuesta

22

Creo que hay casos en los que está bien que aparezcan bucles aparentemente infinitos. Sin embargo, este no parece ser uno de ellos. Parece que usted podría fácilmente escribir el código de la siguiente manera

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; 

Esto parece expresar la verdadera intención del bucle mejor

+5

+1 Para una expresión más clara de intención y función. –

+0

aún podría mejorar al inicializar current_val a map.begin() y agregar a while condición (... && current_val! = It-> second) y tal vez incluso convertir a do-while – stefanB

+0

De acuerdo. Esto es más fácil de leer y menos propenso a errores como resultado. Otro pensamiento con bucles infinitos: a veces no es una idea demasiado mala diseñar algún tipo de escape en el código si puede ser propenso a un comportamiento verdaderamente "infinito". Eso puede ser en forma de verificar la entrada del usuario (el usuario acierta a escapar) o en otras situaciones deteniéndose después de un tiempo de espera predefinido. –

0

Bueno, un comentario diciendo que no es realmente un bucle infinito ayudaría:

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

Estoy de acuerdo en que debería tener una condición, pero esto está bien en algunas situaciones (y no siempre es posible o fácil de hacer una condición).

+0

Si las referencias de alguna manera obtienen una referencia perdida a algo cercano al comienzo de la cadena, se repetirá para siempre. Esto es cierto tanto en la versión de 'ciclo infinito' como en la versión creada por JaredPar. Sin embargo, su versión muestra realmente el intento de bucles en el condicional donde el suyo no lo hace – DevinB

+0

¡Sí! Los comentarios siempre resuelven ese problema. –

+0

Eso es un comentario bastante inútil. No dice bajo qué condiciones regresa, nada. Un buen comentario podría ser que retorna bajo un conjunto específico de condiciones que son demasiado complicadas para ajustarse concisamente dentro de este par de paréntesis, luego enumera las condiciones. Por supuesto, si tuviera que comentarlo claramente, también podría CÓDIGAR eso claramente en el primer caso (que generalmente es el caso) –

6

hay momentos y lugares para bucles infinitos - No estoy convencido de que esto es uno de ellos. Por otro lado, está lejos de ser un problema atroz aquí.

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

Un lugar para usarlos es cuando el proceso es realmente indefinida - un proceso de demonio con un bucle de monitor que no se dará por terminado.

+0

¿Qué sucede si quiero que el daemon deje de funcionar? –

+0

Tiene varias opciones, ya sea interrumpir el ciclo de otra manera indefinido, o llamar a una función de salida que no retorna. Ambos son efectivos. –

+0

Supongo que debería decir 'o romper (o regresar) desde ...' –

5

hay situaciones en que una construcción como esta tiene sentido:

  1. La condición de corte se calcula dentro del bucle
  2. Hay condiciones más de última hora y todos ellos son igualmente importantes
  3. usted realmente desea una bucle infinito;) ..
0

Deje de preocuparse. Esto no está mal si ayuda a simplificar la lógica del código y mejorar el mantenimiento y la legibilidad. Aunque vale la pena documentar en comentarios sobre las condiciones de salida esperadas y sobre por qué el algoritmo no se deslizará en un bucle infinito.

+0

Como mostró JaredPar, realmente no simplifica la lógica. Como dije, documentarlo definitivamente es una buena idea. – Zifre

0

Bueno, sí , pero las dos páginas de código que tiene que escribir si no quiere que su bucle principal a ser algo así como while(true) es aún peor formulario.

1

Aunque ya los he hecho antes, votaría por intentar siempre obtener la solución más clara mediante el uso de algo legible, que generalmente incluiría una expresión válida en el ciclo while; de ​​lo contrario, se está escaneando el código para busca el descanso.

No estoy realmente aterrorizado por ellos ni nada, pero sé que algunas personas sí lo están.

13

Mis dos centavos es: el código debe ser self-documenting. Es decir, cuando se le da un fragmento de código, prefiero poder mirar y decir la intención del programador y luego leer los comentarios o recorrer el código circundante. Cuando leo:

while(true) 

Eso me dice que el programador quería un ciclo infinito; que la condición final no pudo ser especificada. Esta es la intención de los programadores en algunas circunstancias; un bucle de servidor, por ejemplo, y es entonces cuando debería usarse.

En el código anterior, el bucle no está destinado a ser para siempre, tiene una condición final claro, y con el fin de ser semánticamente clara, como otros han señalado:

while (currentVal != searchVal) 

obras, por lo el tiempo (verdadero) es claramente inferior y debería evitarse en este caso.

4

while(true) se usa en juegos para el bucle principal del juego: los juegos leen continuamente la entrada del jugador, procesan las interacciones entre los objetos y pintan la pantalla, luego repiten. Este ciclo continúa infinitamente hasta que otra acción se salga de ese ciclo (salir del juego, terminar el nivel).

He intentado encontrar rápidamente este ciclo principal en el código fuente de Quake 1, pero hubo al menos 50 apariciones de 'while(1)', y algunas escritas como 'for(;;)', y no estaba seguro de inmediato cuál fue el lazo principal del juego.

+0

Me pregunto si este es un muy buen ejemplo de por qué NO se usa mientras (verdadero) ... Quiero decir, si solo lo usaste en los casos que no regresan, sabrías cuál fue el ciclo del juego. Mejor aún, si ese dijo mientras (corriendo), sabría cuál era el verdadero bucle y se comunicaría con el programador exactamente cómo se espera que se detenga (de lo contrario, ¿es un break? Return? Exit? ¿Cuál causará que se ejecute el procedimiento de apagado correcto?) –

+0

La mayoría de los bucles de juego que he visto o escrito son más parecidos a 'while (! Exiting) {...}' – Zifre

+0

'while (running)' probablemente se hubieran visto como un desperdicio de ciclos de CPU: verificar la variable 'running' desperdiciará uno o dos ciclos, y se desperdiciaría aún más esperando a que se lea desde la RAM. –

5

Estoy de acuerdo con las otras respuestas de que no hay necesidad de un bucle infinito en este caso.

Sin embargo, otro punto podría ser que cuando tiene tiene un bucle infinito, for(;;) podría ser una mejor manera de expresarlo. Algunos compiladores generan advertencias para while(true) (la condición siempre se evalúa como falsa), y su intención es menos clara porque se parece a cualquier otro ciclo. Tal vez solía decir while (x == true), y accidentalmente eliminó el x en lugar del true. for(;;) dice bastante claramente que esto tiene la intención de ser un ciclo infinito. O tal vez tenía la intención de escribir algo como while(t), pero Intellisense en su IDE se inició y decidió autocompletar al true.

for(;;) Por otro lado, no es algo que alguna vez escriba accidentalmente. (Y es más fácil de buscar. While (true) también podría ser escrito como mientras (1))

Ninguna de las versiones es equivocada, pero for(;;) podría ser más intuitivo porque no es ninguna condición de bucle.

+0

+1 para explicar la diferencia entre 'for (;;)' y 'while (true)' – pierrotlefou

0

No es raro encontrar bucles infinitos en el código de sistemas integrados - a menudo rodea a las máquinas de estados finitos, comprobando chips y dispositivos periféricos, etc.

0

Me encanta bucles infinitos como la estructura de control fuera de una máquina de estados finitos. Es efectivamente un Goto estructurado:

}

+0

Esto debería seguir como 'while ((int c = ReadInput())!! = EOF) {..}' – Erbureth

+0

Which fuerzas c estar fuera del alcance del bucle o no se puede distinguir entre EOF y error. Los constructos de bucles rellenos no son siempre tu amigo. – plinth