example ejemplos c++ file-io stream filestream

c++ - ejemplos - Ejemplo de por qué stream:: good es incorrecto



bitset c++ example (5)

Di una respuesta que quería verificar la validez del flujo cada vez a través de un bucle aquí .

Mi código original se usa good y se parece a esto:

ifstream foo("foo.txt"); while (foo.good()){ string bar; getline(foo, bar); cout << bar << endl; }

Me señalaron de inmediato y me dijeron que nunca hiciera una good prueba. Claramente, esto es algo que no he entendido, pero quiero hacer correctamente mi E / S de archivos.

Probé mi código con varios ejemplos y no pude hacer que fallara el good código de prueba.

Primero (esto se imprime correctamente, terminando con una nueva línea):

Bleck 1
Blee 1 2
paja
termina en una nueva línea

Segundo (este impreso correctamente, terminando con la última línea):

Bleck 1
Blee 1 2
paja
esto no termina en una nueva línea

El tercero era un archivo vacío (esto se imprimió correctamente, una sola línea nueva).

El cuarto era un archivo faltante (esto no imprimió correctamente nada).

¿Alguien puede ayudarme con un ejemplo que demuestre por qué no se debe hacer una good prueba?


El uso de foo.good() solo te dice que la operación de lectura anterior funcionó bien y que la siguiente también podría funcionar. .good() comprueba el estado de la transmisión en un punto determinado. No verifica si se llega al final del archivo. Digamos que sucedió algo mientras se leía el archivo (error de red, error de os, ...) bueno, fallará. Eso no significa que se llegó al final del archivo. Sin embargo, .good () falla cuando se llega al final del archivo porque la transmisión ya no puede leer.

Por otro lado, .eof() verifica si realmente se llegó al final del archivo.

Entonces, .good() podría fallar mientras no se alcanzaba el final del archivo.

Espero que esto te ayude a entender por qué usar .good() para verificar el final del archivo es un mal hábito.


Esto ya está cubierto en otras respuestas, pero lo revisaré brevemente para completarlo. La única diferencia funcional con

while(foo.good()) { // effectively same as while(foo) { getline(foo, bar); consume(bar); // consume() represents any operation that uses bar }

Y

while(getline(foo, bar)){ consume(bar); }

Es que el primero hará un bucle adicional cuando no haya líneas en el archivo, haciendo que ese caso no se distinga del caso de una línea vacía. Yo diría que esto no es típicamente el comportamiento deseado. Pero supongo que es cuestión de opinión.

Como dice Sehe, el mantra está por la borda . Es una simplificación. De lo que realmente se trata es de que no debe consume() el resultado de leer la secuencia antes de probar la falla o al menos EOF (y cualquier prueba antes de que la lectura sea ​​irrelevante). Que es lo que las personas hacen fácilmente cuando prueban good() en la condición de bucle.

Sin embargo, lo que pasa con getline() es que prueba EOF internamente, para usted y devuelve una cadena vacía incluso si solo se lee EOF. Por lo tanto, la versión anterior podría ser más o menos similar a la siguiente pseudoc ++:

while(foo.good()) { // inside getline bar = ""; // Reset bar to empty string sentry; if(read_until_newline(foo, sentry)) { // The streams state is tested implicitly inside getline // after the value is read. Good bar = sentry // The read value is used only if it''s valid. // ... // Otherwise, bar is empty. consume(bar); }

Espero que eso ilustre lo que trato de decir. Se podría decir que hay una versión "correcta" del ciclo de lectura dentro de getline() . Esta es la razón por la cual la regla se satisface al menos parcialmente con el uso de readline incluso si el bucle externo no se ajusta.

Pero, para otros métodos de lectura, romper la regla duele más. Considerar:

while(foo.good()) { int bar; foo >> bar; consume(bar); }

¡No solo siempre obtienes la iteración adicional, la bar en esa iteración no está inicializada!

Así que, en resumen, while(foo.good()) está bien en su caso, porque getline() diferencia de otras funciones de lectura, deja el resultado en un estado válido después de leer el bit EOF. y porque no le importa o incluso espera la iteración adicional cuando el archivo está vacío.


tanto good() como eof() le darán una línea adicional en su código. Si tienes un archivo en blanco y ejecuta esto:

std::ifstream foo1("foo1.txt"); std::string line; int lineNum = 1; std::cout << "foo1.txt Controlled With good():/n"; while (foo1.good()) { std::getline(foo1, line); std::cout << lineNum++ << line << std::endl; } foo1.close(); foo1.open("foo1.txt"); lineNum = 1; std::cout << "/n/nfoo1.txt Controlled With getline():/n"; while (std::getline(foo1, line)) { std::cout << line << std::endl; }

El resultado que obtendrá es

foo1.txt Controlled With good(): 1 foo1.txt Controlled With getline():

Esto demuestra que no está funcionando correctamente, ya que un archivo en blanco nunca debe leerse. La única manera de saberlo es usar una condición de lectura ya que la transmisión siempre será buena la primera vez que se lee.


Ellos estaban equivocados. El mantra es ''nunca prueba .eof() ''.

Incluso ese mantra está por la borda, porque ambos son útiles para diagnosticar el estado de la secuencia después de que falló una extracción.

Entonces el mantra debería ser más como

No use good() o eof() para detectar eof antes de intentar leer más

Lo mismo para fail() y bad()

Por supuesto, stream.good puede utilizar de manera útil antes de usar una transmisión (por ejemplo, en el caso de que la transmisión sea una ruta de archivos que no se haya abierto correctamente)

Sin embargo, ambos son muy muy a menudo maltratados para detectar el final de la entrada, y no es así como funciona.

Un ejemplo canónico de por qué no deberías usar este método:

std::istringstream stream("a"); char ch; if (stream >> ch) { std::cout << "At eof? " << std::boolalpha << stream.eof() << "/n"; std::cout << "good? " << std::boolalpha << stream.good() << "/n"; }

Huellas dactilares

false true

Véalo en vivo en Coliru


Permítanme decir claramente que la respuesta de Sehe es la correcta.

Pero la opción propuesta por Nathan Oliver , Neil Kirk y user2079303 es usar readline como la condición de bucle en lugar de good . Debe ser abordado por el bien de la posteridad.

Compararemos el ciclo en la pregunta con el siguiente ciclo:

string bar; while (getline(foo, bar)){ cout << bar << endl; }

Porque getline devuelve el istream pasado como el primer argumento, y porque cuando un istream se istream en bool , !(fail() || bad()) vuelve !(fail() || bad()) , y desde que lee el carácter EOF establecerá tanto el failbit como el eofbit esto hace getline una condición de bucle válida.

Sin embargo, el comportamiento cambia cuando se usa getline como condición, ya que si se lee una línea que contiene solo un carácter EOF, el ciclo saldrá para evitar que se genere esa línea. Esto no ocurre en los ejemplos 2 y 4. Pero el ejemplo 1:

Bleck 1
Blee 1 2
paja
termina en una nueva línea

Imprime esto con la good condición de bucle:

Bleck 1
Blee 1 2
paja
termina en una nueva línea

Pero corta la última línea con la condición getline loop:

Bleck 1
Blee 1 2
paja
termina en una nueva línea

El ejemplo 3 es un archivo vacío:

Imprime esto con las good condiciones:

No imprime nada con la condición getline .

Ninguno de estos comportamientos es incorrecto. Pero esa última línea puede hacer una diferencia en el código. Esperemos que esta respuesta sea útil para usted al decidir entre los dos para fines de codificación.