Soy un programador autodidacta. Empecé a programar hace aproximadamente 1,5 años. Ahora he comenzado a tener clases de programación en la escuela. Hemos tenido clases de programación durante 1/2 año y tendremos otro 1/2 en este momento.
En las clases estamos aprendiendo a programar en C ++ (que es un lenguaje que ya sabía que usaba bastante bien antes de comenzar).
No he tenido ninguna dificultad durante esta clase, pero hay un problema recurrente para el que no he podido encontrar una solución clara.
El problema es así (en pseudocódigo):
do something
if something failed:
handle the error
try something (line 1) again
else:
we are done!
Aquí hay un ejemplo en C ++
El código solicita al usuario que ingrese un número y lo hace hasta que la entrada sea válida. Se utiliza cin.fail()
para verificar si la entrada no es válida. Cuándo cin.fail()
es true
que tengo que llamar cin.clear()
y cin.ignore()
poder continuar recibiendo información de la transmisión.
Soy consciente de que este código no verifica
EOF
. No se espera que los programas que hemos escrito hagan eso.
Así es como escribí el código en una de mis tareas en la escuela:
for (;;) {
cout << ": ";
cin >> input;
if (cin.fail()) {
cin.clear();
cin.ignore(512, '\n');
continue;
}
break;
}
Mi maestra dijo que no debería estar usando break
y continue
así. Me sugirió que debería usar un regular while
o un do ... while
bucle en su lugar.
Me parece que usar break
y continue
es la forma más sencilla de representar este tipo de bucle. De hecho, lo pensé durante bastante tiempo, pero realmente no se me ocurrió una solución más clara.
Creo que él quería que yo hiciera algo como esto:
do {
cout << ": ";
cin >> input;
bool fail = cin.fail();
if (fail) {
cin.clear();
cin.ignore(512, '\n');
}
} while (fail);
Para mí, esta versión parece mucho más compleja ya que ahora también tenemos variables llamadas fail
para realizar un seguimiento y la verificación de fallas de entrada se realiza dos veces en lugar de solo una.
También pensé que podía escribir el código de esta manera (abusando de la evaluación de cortocircuito):
do {
cout << ": ";
cin >> input;
if (fail) {
cin.clear();
cin.ignore(512, '\n');
}
} while (cin.fail() && (cin.clear(), cin.ignore(512, '\n', true);
Esta versión funciona exactamente como las otras. No utiliza break
o continue
y la cin.fail()
prueba solo se realiza una vez. Sin embargo, no me parece correcto abusar de la "regla de evaluación de cortocircuito" como esta. Tampoco creo que a mi maestra le guste.
Este problema no solo se aplica solo a la cin.fail()
comprobación. He usado break
y me continue
gusta esto para muchos otros casos que implican repetir un conjunto de código hasta que se cumpla una condición en la que también se debe hacer algo si la condición no se cumple (como llamar cin.clear()
y cin.ignore(...)
del cin.fail()
ejemplo).
He seguido usando break
y continue
durante todo el curso y ahora mi maestro ha dejado de quejarse al respecto.
¿Cuáles son tus opiniones sobre esto?
¿Crees que mi maestro tiene razón?
¿Conoces una mejor manera de representar este tipo de problema?
while (true)
y al instante asumir que hay una break
, return
o throw
en algún lugar allí. La introducción de una variable adicional que debe mantenerse un registro de sólo para esquivar una break
o continue
es contraproducente. Yo diría que el problema con el código inicial es que el ciclo nunca termina una iteración normalmente, y que necesita saber que hay un continue
adentro if
para saber break
que no se tomará.
dataIsValid
es mutable, por lo que para saber que el ciclo termina correctamente, necesito verificar que esté configurado cuando los datos son válidos, y también que no esté desarmado en ningún momento posterior. En un bucle de la forma do { ... if (!expr) { break; } ... } while (true);
, sé que si se expr
evalúa como false
, el bucle se romperá sin tener que mirar el resto del cuerpo del bucle.