sirve que para c++ stream

que - cout flush c++



¿Cómo funciona std:: flush? (4)

Aquí hay un programa corto que puedes escribir para observar lo que está haciendo el rubor

#include <iostream> #include <unistd.h> using namespace std; int main() { cout << "Line 1..." << flush; usleep(500000); cout << "/nLine 2" << endl; cout << "Line 3" << endl ; return 0; }

Ejecute este programa: verá que imprime la línea 1, hace una pausa, luego imprime la línea 2 y 3. Ahora borre la llamada de descarga y vuelva a ejecutar el programa; verá que el programa hace una pausa y luego imprime las 3 líneas al Mismo tiempo. La primera línea se almacena en el búfer antes de que el programa se detenga, pero debido a que el búfer nunca se vacía, la línea 1 no se emite hasta la llamada final desde la línea 2.

¿Alguien puede explicar (preferiblemente con un inglés sencillo) cómo funciona std::flush ?

  • ¿Qué es?
  • ¿Cuándo limpiarías una corriente?
  • ¿Por qué es importante?

Gracias.


Como no se contestó qué es std::flush , aquí hay algunos detalles sobre lo que realmente es. std::flush es un manipulador , es decir, una función con una firma específica. Para empezar simple, puede pensar en std::flush de tener la firma

std::ostream& std::flush(std::ostream&);

Sin embargo, la realidad es un poco más compleja (si está interesado, se explica a continuación también).

Los operadores de salida de sobrecarga de clase de flujo toman operadores de esta forma, es decir, hay una función de miembro que toma un manipulador como argumento. El operador de salida llama al manipulador con el objeto mismo:

std::ostream& std::ostream::operator<< (std::ostream& (*manip)(std::ostream&)) { (*manip)(*this); return *this; }

Es decir, cuando " std::ostream " std::flush with a std::ostream , simplemente llama a la función correspondiente, es decir, las dos declaraciones siguientes son equivalentes:

std::cout << std::flush; std::flush(std::cout);

Ahora, std::flush() sí mismo es bastante simple: todo lo que hace es llamar a std::ostream::flush() , es decir, puede visualizar su implementación para que se vea así:

std::ostream& std::flush(std::ostream& out) { out.flush(); return out; }

La función std::ostream::flush() llama técnicamente a std::streambuf::pubsync() en el búfer de flujo (si existe) que está asociado con la secuencia: El búfer de secuencia es responsable de almacenar en el búfer los caracteres y enviar caracteres al el destino externo cuando el búfer usado se desborda o cuando la representación interna debe sincronizarse con el destino externo, es decir, cuando los datos se van a enjuagar. En una secuencia de sincronización de flujo con el destino externo solo significa que cualquier carácter almacenado en el búfer se envía inmediatamente. Es decir, usar std::flush hace que el buffer de flujo vacíe su buffer de salida. Por ejemplo, cuando los datos se escriben en una consola, el enjuague hace que los caracteres aparezcan en este punto en la consola.

Esto puede plantear la pregunta: ¿por qué no se escriben caracteres inmediatamente? La respuesta simple es que escribir caracteres generalmente es bastante lento. Sin embargo, la cantidad de tiempo que lleva escribir una cantidad razonable de caracteres es esencialmente idéntica a escribir solo una donde. La cantidad de caracteres depende de muchas características del sistema operativo, sistemas de archivos, etc., pero a menudo se escriben hasta 4k caracteres aproximadamente al mismo tiempo que un solo personaje. Por lo tanto, almacenar en memoria intermedia los caracteres antes de enviarlos usando un búfer dependiendo de los detalles del destino externo puede representar una gran mejora en el rendimiento.

Lo anterior debe responder dos de tus tres preguntas. La pregunta restante es: ¿cuándo vaciar un flujo? La respuesta es: ¡cuando los caracteres se escriban en el destino externo! Esto puede ser al final de la escritura de un archivo (sin embargo, el archivo implícitamente vacía el búfer) o inmediatamente antes de solicitar la entrada del usuario (tenga en cuenta que std::cout se vacía automáticamente al leer std::cin como std::cout es std::istream::tie() ''d a std::cin ). Aunque puede haber algunas ocasiones en las que explícitamente desee descargar una secuencia, creo que son bastante raras.

Finalmente, prometí dar una idea completa de qué es std::flush realidad: las secuencias son plantillas de clase capaces de tratar con diferentes tipos de caracteres (en la práctica funcionan con char y wchar_t ; hacer que trabajen con otros personajes es bastante complicado, aunque factible si estás realmente determinado). Para poder usar std::flush con todas las instancias de flujos, resulta ser una plantilla de función con una firma como esta:

template <typename cT, typename Traits> std::basic_ostream<cT, Traits>& std::flush(std::basic_ostream<cT, Traits>&);

Al usar std::flush inmediatamente con una instanciación de std::basic_ostream , realmente no importa: el compilador deduce automáticamente los argumentos de la plantilla. Sin embargo, en los casos donde esta función no se menciona junto con algo que facilite la deducción del argumento de la plantilla, el compilador no podrá deducir los argumentos de la plantilla.


De forma predeterminada, std::cout está almacenado en búfer, y la salida real solo se imprime una vez que el búfer está lleno o se produce alguna otra situación de descarga (por ejemplo, una nueva línea en la transmisión). En ocasiones, querrás asegurarte de que la impresión se realice de inmediato, y debes enjuagar manualmente.

Por ejemplo, supongamos que desea informar un informe de progreso imprimiendo un solo punto:

for (;;) { perform_expensive_operation(); std::cout << ''.''; std::flush(std::cout); }

Sin el enjuague, no verías la salida durante mucho tiempo.

Tenga en cuenta que std::endl inserta una línea nueva en una secuencia y también hace que se vacíe. Debido a que el enjuague es levemente costoso, std::endl no debe usarse en exceso si no se desea expresamente el enjuague.


Una corriente está conectada a algo. En el caso de la salida estándar, podría ser la consola / pantalla o podría ser redirigido a una tubería o un archivo. Hay un montón de código entre su programa y, por ejemplo, el disco duro donde se almacena el archivo. Por ejemplo, el sistema operativo está haciendo cosas con cualquier archivo o la propia unidad de disco puede almacenar datos en búfer para poder escribirlos en bloques de tamaño fijo o simplemente para ser más eficientes.

Cuando descarga la secuencia, le dice a las bibliotecas de idiomas, el sistema operativo y el hardware que desea que los caracteres que ha generado hasta ahora sean forzados hasta el almacenamiento. Teóricamente, después de una "descarga", podría patear el cable fuera de la pared y esos caracteres aún se almacenarían de manera segura.

Debo mencionar que las personas que escriben los controladores del sistema operativo o las personas que diseñan la unidad de disco pueden utilizar ''flujo'' como sugerencia y es posible que no escriban realmente los caracteres. Incluso cuando la salida está cerrada, pueden esperar un tiempo para guardarlos. (Recuerde que el sistema operativo hace todo tipo de cosas a la vez y que podría ser más eficiente esperar uno o dos segundos para manejar sus bytes).

Entonces un color es una especie de punto de control.

Un ejemplo más: si la salida va a la pantalla de la consola, un color se asegurará de que los personajes lleguen a donde el usuario pueda verlos. Esto es algo importante que debe hacer cuando espera la entrada del teclado. Si cree que ha escrito una pregunta en la consola y todavía está atascada en algún búfer interno, el usuario no sabrá qué escribir en la respuesta. Entonces, este es un caso donde el color es importante.