Semántica de banderas en basic_ios

Me encuentro rdstate() desconcertado por los rdstate()good() , bad() , eof() , fail() – y cómo se expresan en basic_ios::operator! , operator bool y operator void* .

¿Podría alguien sacarme de mi miseria y explicarme esto para que nunca tenga que pensar dos veces?

Hay tres indicadores que indican estado de error:

  • badbit significa que algo ha ido muy mal con la transmisión. Puede ser un error de búfer o un error en lo que sea que esté alimentando datos a la transmisión. Si esta bandera está configurada, es probable que ya no vaya a utilizar la transmisión.

  • failbit significa que una extracción o una lectura de la secuencia fallaron (o una escritura o inserción de flujos de salida) y usted debe conocer esa falla.

  • eofbit significa que el flujo de entrada ha llegado a su fin y no queda nada por leer. Tenga en cuenta que esto se establece solo después de intentar leer de una secuencia de entrada que ha llegado a su final (es decir, se establece cuando se produce un error porque intenta leer datos que no están allí).

El failbit también puede ser configurado por muchas operaciones que alcanzan EOF. Por ejemplo, si solo queda un espacio en blanco en la secuencia e intenta leer un int , ambos alcanzarán EOF y no podrán leer el int , por lo que se establecerán ambos indicadores.

La función fail() prueba badbit || failbit badbit || failbit .

Las pruebas de función good() !(badbit || failbit || eofbit) . Es decir, una transmisión es buena cuando no se establece ninguno de los bits.

Puede restablecer los indicadores utilizando la función de miembro ios::clear() ; esto le permite establecer cualquiera de los indicadores de error; por defecto (sin argumento), borra los tres indicadores.

Las transmisiones no sobrecargan el operator bool() ; operator void*() se usa para implementar una versión algo rota de la expresión de bool seguro. Esta sobrecarga del operador devuelve nulo si se establece badbit o failbit , y no es nulo en caso contrario. Puede utilizar esto para respaldar la expresión idiomática de probar el éxito de una extracción como condición de un bucle u otro enunciado de flujo de control:

 if (std::cin >> x) { // extraction succeeded } else { // extraction failed } 

La sobrecarga del operator!() Es lo opuesto al operator void*() del operator void*() ; devuelve true si el badbit o failbit está configurado y false contrario. La sobrecarga del operator!() Ya no es necesaria; data de antes de que las sobrecargas del operador fueran soportadas completa y consistentemente (vea la pregunta de sbi “¿Por qué std :: basic_ios sobrecarga el operador de negación lógica unario?” ).

C ++ 0x soluciona el problema que causa que tengamos que usar la expresión de bool seguro, por lo que en C ++ 0x la plantilla de clase base basic_ios sobrecarga al operator bool() como un operador de conversión explícito; este operador tiene la misma semántica que el operator void*() actual operator void*() .

Además de la respuesta de James , es importante recordar que estos indicadores indican los resultados de las operaciones, por lo que no se establecerán a menos que realice uno.

Un error común es hacer esto:

 #include  #include  #include  int main() { std::ifstream file("main.cpp"); while (!file.eof()) // while the file isn't at eof... { std::string line; std::getline(file, line); // ...read a line... std::cout << "> " << line << std::endl; // and print it } } 

El problema aquí es que eof() no se establecerá hasta después de que tratemos de obtener la última línea, en cuyo momento la transmisión dirá "¡no, no más!" y establecerlo. Esto significa que la forma "correcta" es:

 #include  #include  #include  int main() { std::ifstream file("main.cpp"); for (;;) { std::string line; std::getline(file, line); // read a line... if (file.eof()) // ...and check if it we were at eof break; std::cout << "> " << line << std::endl; } } 

Esto coloca el cheque en la ubicación correcta. Esto es muy rebelde sin embargo; afortunadamente para nosotros, el valor de retorno para std::getline es la secuencia, y la secuencia tiene un operador de conversión que permite que se pruebe en un contexto booleano, con el valor de fail() , que incluye eof() . Entonces podemos escribir:

 #include  #include  #include  int main() { std::ifstream file("main.cpp"); std::string line; while (std::getline(file, line)) // get line, test if it was eof std::cout << "> " << line << std::endl; }