24 de noviembre de 2012
Parte inferior de la línea de arriba: Con el manejo adecuado de espacio en blanco, el siguiente es cómo eof
pueden ser utilizados (e incluso, ser más fiable que la de fail()
para la comprobación de errores):
while( !(in>>std::ws).eof() ) {
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
(Gracias Tony D por la sugerencia para resaltar la respuesta. Ver su comentario a continuación un ejemplo de por qué esto es más robusto.)
El principal argumento en contra del uso de eof()
parece estar perdiendo una importante sutileza sobre el papel del espacio en blanco. Mi propuesta es que, la comprobación de eof()
explícitamente no sólo no es "siempre es malo", lo cual parece ser una opinión preponderante en esta y similares PARA hilos --, pero con el manejo adecuado de espacio en blanco, se ofrece para una mejor y más confiable en el manejo de errores, y es la siempre correcta solución (aunque no necesariamente la tersest).
Para resumir lo que se propone como la "correcta" terminación y leer el orden es el siguiente:
int data;
while(in >> data) { /* ... */ }
// which is equivalent to
while( !(in >> data).fail() ) { /* ... */ }
El fracaso debido a un intento de lectura más allá de la eof se considera la condición de terminación. Esto significa que no hay ninguna manera fácil de distinguir entre un exitoso corriente y que realmente falla por otras razones que la ef. Tome las siguientes corrientes:
1 2 3 4 5<eof>
1 2 a 3 4 5<eof>
a<eof>
while(in>>data)
termina con un conjunto failbit
para todos los tres de entrada. En la primera y la tercera, eofbit
también se establece. Así que pasado el bucle uno necesita muy feo lógica adicional para distinguir una entrada correcta (1) inadecuado (de 2ª y 3ª).
Considerando, que tome las siguientes:
while( !in.eof() )
{
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
Aquí, in.fail()
comprueba que siempre hay algo para leer, es la correcta. Su propósito no es un simple bucle while terminator.
Hasta aquí bien, pero ¿qué pasa si no hay espacio al final de la secuencia -- lo que suena como el tema de mayor preocupación en contra eof()
como terminator?
No tenemos que entregar nuestra manejo de errores; sólo se comen el espacio en blanco:
while( !in.eof() )
{
int data;
in >> data >> ws; // eat whitespace with std::ws
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
std::ws
omite cualquier potencial (cero o más) espacio al final de la secuencia, mientras que la configuración de la eofbit
, y no la failbit
. Así, in.fail()
funciona como se espera, siempre y cuando al menos uno de los datos a leer. Si todo en blanco corrientes también son aceptables, entonces la forma correcta es:
while( !(in>>ws).eof() )
{
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
/* this will never fire if the eof is reached cleanly */
// now use data
}
Resumen: Un bien construido while(!eof)
es no sólo posible, y no se equivocan, pero permite que los datos que se localiza dentro de alcance, y proporciona una separación más clara de comprobación de error de los negocios como de costumbre. Que siendo dicho, while(!fail)
es sin lugar a dudas más comunes y conciso de modismos, y puede ser preferible en simples (una sola datos por leer tipo de) de los escenarios.