Acabo de encontrar un comentario en este respuesta diciendo que el uso de iostream::eof en una condición de bucle es «casi ciertamente malo». Yo generalmente uso algo como while(cin>>n) – que supongo que implícitamente cheques para las expresiones del FOLCLORE.

¿Por qué es la comprobación de ef de forma explícita el uso de while (!cin.eof()) mal?

¿Cómo es diferente del uso de scanf("...",...)!=EOF en C (que a menudo utilizo sin problemas)?

  • scanf(...) != EOF no funciona en la C, porque scanf devuelve el número de campos de analizar correctamente asignados. La correcta condición es scanf(...) < n donde n es el número de campos en la cadena de formato.
  • Voigt, que nos devuelve un número negativo (que EF es generalmente definido como tal) en el caso de EF se alcanza
  • En realidad, se devolverá EOF si al final del archivo se encuentra antes de la primera conversión en campo (con éxito o no). Si es fin de archivo se alcanza entre los campos, se le devolverá el número de campos succcessfully convierten y almacenan. Lo cual dificulta la comparación de EOF mal.
  • No, realmente no. Él yerra cuando dice que «pasado el bucle no es (fácil) manera de distinguir una entrada correcta de una incorrecta uno». De hecho, es tan fácil como seleccionar .eof() después de que el bucle termina.
  • Sí, para este caso (la lectura de un simple int). Pero uno puede fácilmente llegar a un escenario donde la while(fail) bucle termina con un error real y un ef. Piense acerca de si se requieren 3 ints por iteración (digamos que usted está leyendo x-y-z punto o algo), pero no es, erróneamente, sólo dos puntos en la secuencia.
  • Este problema es análogo a y tiene la misma respuesta como el C pregunta: ¿por Qué while(!feof(file)) es siempre malo?. Debido a que el indicador se establece sólo después de golpear la EF.
  • Aquí el C++ preguntas frecuentes tomar sobre la misma cuestión.
  • es que «3 puntos» escenario no se controlan correctamente por while (in >> x) { if (in >> y >> z) use(x, y, z); else FATAL("got an int not followed by 2 more!"); } if (!eof()) FATAL("didn't get integer where expected");? Si no, ¿para qué secuencia de contenidos que no funcionan bien?
  • Esta pregunta fue publicado sin atribución en Quora: quora.com/unanswered/… (la Quora pregunta del título coincide exactamente con el título de esta pregunta tenía antes de ser editado el día de ayer).

InformationsquelleAutor MAK | 2011-04-09

4 Comentarios

  1. 506

    Porque iostream::eof sólo devolverá true después de de leer el final de la secuencia. No no indicar, que la próxima lectura será el final de la secuencia.

    Considerar este (y asumir entonces la próxima lectura será al final de la secuencia):

    while(!inStream.eof()){
      int data;
      //yay, not end of stream yet, now read ...
      inStream >> data;
      //oh crap, now we read the end and *only* now the eof bit will be set (as well as the fail bit)
      //do stuff with (now uninitialized) data
    }

    Contra esto:

    int data;
    while(inStream >> data){
      //when we land here, we can be sure that the read was successful.
      //if it wasn't, the returned stream from operator>> would be converted to false
      //and the loop wouldn't even be entered
      //do stuff with correctly initialized data (hopefully)
    }

    Y sobre tu segunda pregunta: Porque

    if(scanf("...",...)!=EOF)

    es el mismo que

    if(!(inStream >> data).eof())

    y no la misma como

    if(!inStream.eof())
        inFile >> data
    • Vale la pena mencionar es que si (!(inStream >> datos).eof()) no hacer nada útil. Falacia 1: no entrar en la condición si no hay un espacio en blanco después de la última pieza de datos (último dato no será procesada). Falacia 2: va a entrar el estado, incluso si la lectura de los datos de error, siempre y cuando EF no se alcanzó (bucle infinito, el procesamiento de la misma edad de los datos una y otra vez).
    • Un poco fuera de tema pero me deja ponerlo. Si uno utiliza la evaluación diferida, sería este enfoque correctamente sin ningún problema?
    • Creo que vale la pena señalar que esta respuesta es un poco engañoso. Cuando la extracción de ints o std::strings o similares, la EF bits es definir al extraer el uno a la derecha antes de la final y la extracción llega al final. Usted no tiene que leer de nuevo. La razón por la que no se establecerá cuando la lectura de los archivos es porque hay un extra de \n al final. He cubierto esta en otra respuesta. La lectura de chars es un asunto diferente, ya que sólo extractos de una en una y no seguir pegado a la final.
    • El principal problema es que sólo porque no hemos llegado a la EF, no significa que la próxima lectura tendrá éxito.
    • todo cierto, pero no es muy útil… incluso si no hay tirados ‘\n’ es razonable querer otros tirados, en el espacio en blanco para ser manejado de forma consistente con otros espacios en blanco en todo el archivo (es decir, omite). Además, una sutil consecuencia de «al extraer el uno a la derecha antes de» es que while (!eof()) no «funciona» en la ints o std::strings cuando la entrada está totalmente vacía, por lo que incluso sabiendo que no hay tirados \n de cuidado necesario.
    • Totalmente de acuerdo. La razón por la que digo esto es porque creo que la mayoría de las personas cuando leen esto y respuestas similares se piensa que si la secuencia contiene "Hello" (no trailing espacio en blanco o \n) y un std::string se extrae, se va a extraer las cartas de H a o, dejar de extraer y, a continuación, no conjunto de la EF poco. De hecho, se podría establecer la EF poco porque era la EF que se detuvo la extracción. Sólo la esperanza de aclarar eso para la gente.
    • Esta respuesta debería ser wiki gustaría, no pasa un día, cuando alguien no publicar este antipattern.
    • También vale la pena mencionar. Si no hay datos no válidos en la entrada de la lectura puede provocar que el flujo de ir a un mal estado. Esto evitará leer más (a menos que explícitamente se borra). La prueba while(!inStream.eof()) continuación, entrar en un bucle infinito (ya que no hay datos de lectura y nunca llega a ef).
    • // do stuff with (now uninitialized) data Que no es cierto como lo de C++11, consulte stackoverflow.com/a/13379073/3002139

  2. 98

    Parte inferior de la línea de arriba: Con el manejo adecuado de espacio en blanco, el siguiente es cómo eof puede ser utilizada (e incluso, ser más fiable que 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 mal» — lo que 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 el 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 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ª).

    Mientras 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 de 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 construidos, while(!eof) no sólo es 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. Dicho esto, 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.

    • «Así que pasado el bucle no es (fácil) manera de distinguir una entrada correcta de una incorrecta uno.«, Salvo que en un caso tanto eofbit y failbit se establecen, en el otro sólo failbit se establece. Usted sólo necesita probar que al después de que el ciclo ha terminado, no en cada iteración; sólo salir del bucle una vez, tan sólo tendrá que comprobar porque a la izquierda el bucle una vez. while (in >> data) funciona bien para todos en blanco arroyos.
    • Lo que usted está diciendo (y un punto que se hizo anteriormente) es que un mal formato de flujo puede ser identificado como !eof & fail pasado bucle. Hay casos en los que uno no puede depender de esto. Véase el comentario de arriba (goo.gl/9mXYX). Eitherway, no estoy proponiendo eof-revisar como la-siempre-mejor alternativa. Simplemente estoy diciendo, que está una posible y (en algunos casos más apropiado) una manera de hacer esto, en lugar de «ciertamente equivocado!», ya que tiende a ser reclamado por aquí en tanto.
    • «Como un ejemplo, considere cómo se había de verificación de errores de los datos es una estructura con operador sobrecargado>> la lectura de varios campos a la vez» – mucho más simple caso de apoyar su punto de stream >> my_int donde la secuencia contiene por ejemplo,» -«: eofbit y failbit se establecen. Que es peor que la operator>> escenario, donde el usuario proporcionado por la sobrecarga de, al menos, tiene la opción de compensación eofbit antes de regresar para ayudar a apoyar while (s >> x) de uso. De manera más general, esta respuesta podría utilizar una limpia – sólo el final while( !(in>>ws).eof() ) es generalmente robusto, y es enterrado en el extremo.
    • .. de hecho. Gracias. He actualizado la respuesta.
  3. 67

    Porque si los programadores no escribir while(stream >> n), que posiblemente escribir esto:

    while(!stream.eof())
    {
        stream >> n;
        //some work on n;
    }

    Aquí el problema es que no se puede hacer some work on n sin comprobar primero si la secuencia de lectura fue un éxito, porque si no tuvo éxito, su some work on n produciría un resultado no deseado.

    El punto es que, eofbit, badbit, o failbit se establecen después de un intento de lectura de la secuencia. Así que si stream >> n falla, entonces eofbit, badbit, o failbit se establece de inmediato, así que es más idiomático, si usted escribe while (stream >> n), porque el objeto devuelto stream convierte a false si hubo algún fallo en la lectura de la secuencia y, en consecuencia, el bucle se detiene. Y que se convierte en true si la lectura fue un éxito y el bucle continúa.

    • Aparte de los mencionados «resultado no deseado» con haciendo un trabajo sobre el valor indefinido de n, el programa también puede caer en un bucle infinito, si la falta de flujo de operación de no consumir ninguna entrada.
  4. 2

    Las otras respuestas han explicado por qué la lógica que está mal en while (!stream.eof()) y cómo solucionarlo. Quiero centrarme en algo diferente:

    ¿por qué es la comprobación de ef de forma explícita el uso de iostream::eof mal?

    En términos generales, la comprobación de eof sólo es equivocada porque la secuencia de extracción (>>) pueden fallar sin golpear al final del archivo. Si usted tiene por ejemplo, int n; cin >> n; y la secuencia contiene hello, entonces h no es un dígito válido, por lo que la extracción se producirá sin necesidad de llegar a la final de la entrada.

    Este problema, combinado con la lógica general de error de comprobación de la corriente de estado antes de intentar leer de ella, lo cual significa que para N de entrada de los elementos que el bucle se ejecute N+1 veces, provoca los siguientes síntomas:

    • Si la secuencia está vacía, el bucle se ejecuta una vez. >> fallará (no hay ninguna entrada para ser leído) y todas las variables que se suponía que iban a ser fijado por el stream >> x) son en realidad sin inicializar. Esto conduce a la basura datos a ser procesados, que puede manifestarse como falta de sentido de los resultados (a menudo, grandes números).

    • Si la secuencia no está vacía, el bucle se ejecute de nuevo después de la última entrada válida. Ya que en la última iteración todos los >> operaciones no, las variables son propensos a mantener su valor a partir de la iteración anterior. Esto puede manifestarse como «la última línea se imprime dos veces» o «el último registro de entrada se procesa dos veces».

    • Si la secuencia contiene datos con formato incorrecto, pero sólo puedes comprobar .eof, usted termina con un bucle infinito. >> fallará extraer todos los datos de la secuencia, por lo que el bucle tiradas en el lugar, sin llegar nunca a la final.


    Para recapitular: La solución es poner a prueba el éxito de la >> operación en sí misma, no usar un .eof() método: while (stream >> n >> m) { ... }, al igual que en C se prueba el éxito de la scanf se llame a sí mismo: while (scanf("%d%d", &n, &m) == 2) { ... }.

Dejar respuesta

Please enter your comment!
Please enter your name here