Parte superior de la línea inferior: con el manejo adecuado del espacio en blanco, lo siguiente es cómo eof
se puede usar (e incluso, ser más confiable que fail()
para la verificació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 de resaltar la respuesta. Vea su comentario a continuación para ver un ejemplo de por qué esto es más robusto ) .
Al argumento principal en contra del uso eof()
parece faltarle una sutileza importante sobre el papel del espacio en blanco. Mi propuesta es que, verificar eof()
explícitamente no solo no es " siempre incorrecto ", lo que parece ser una opinión primordial en este y otros hilos SO similares, sino que, con un manejo adecuado del espacio en blanco, proporciona un espacio más limpio y más confiable manejo de errores, y es la solución siempre correcta (aunque, no necesariamente la más estricta).
Para resumir lo que se sugiere como la terminación "correcta" y el orden de lectura es el siguiente:
int data;
while(in >> data) { /* ... */ }
// which is equivalent to
while( !(in >> data).fail() ) { /* ... */ }
La falla debida al intento de lectura más allá de eof se toma como la condición de terminación. Esto significa que no hay una manera fácil de distinguir entre una transmisión exitosa y una que realmente falla por otras razones que no sean eof. Tome las siguientes transmisiones:
1 2 3 4 5<eof>
1 2 a 3 4 5<eof>
a<eof>
while(in>>data)
termina con un conjunto failbit
para las tres entradas. En el primero y tercero, eofbit
también se establece. Entonces, más allá del bucle, uno necesita una lógica extra muy fea para distinguir una entrada adecuada (primera) de las incorrectas (segunda y tercera).
Mientras que, tome lo siguiente:
while( !in.eof() )
{
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
Aquí, in.fail()
verifica que mientras haya algo para leer, es el correcto. Su propósito no es un simple terminador while-loop.
Hasta ahora todo bien, pero ¿qué sucede si hay un espacio final en la secuencia? ¿Cuál parece ser la principal preocupación contra el eof()
terminador?
No necesitamos entregar nuestro manejo de errores; solo come 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 espacio final potencial (cero o más) en la secuencia al configurar eofbit
y no elfailbit
. Por lo tanto, in.fail()
funciona según lo esperado, siempre que haya al menos un dato para leer. Si las secuencias en blanco 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: Una construcción adecuada while(!eof)
no solo es posible y no está mal, sino que permite que los datos se localicen dentro del alcance y proporciona una separación más clara de la verificación de errores de la empresa como de costumbre. Dicho esto, while(!fail)
es indiscutiblemente un lenguaje más común y conciso, y puede preferirse en escenarios simples (datos únicos por tipo de lectura).
scanf(...) != EOF
tampoco funcionará en C, porquescanf
devuelve el número de campos analizados y asignados correctamente. La condición correcta esscanf(...) < n
dónden
está el número de campos en la cadena de formato.