parte - limpiar variables en c++
Las consecuencias y los pros/contras de limpiar la corriente en c++ (5)
Cuando se produce el almacenamiento en búfer, no tendrá garantías de que los datos se reciban inmediatamente antes de que se produzca un vaciado. En circunstancias particulares, puede experimentar un orden de salida incorrecto y / o pérdida de información / datos de depuración, por ejemplo
int main() {
std::cout << "This text is quite nice and might as well be buffered";
raise(SIGSEGV); // Oh dear.. segmentation violation
std::cout << std::endl;
}
Salida:
bash: line 7: 22235 Segmentation fault (core dumped) ./a.out
lo anterior no imprimirá ningún texto ya que el búfer impidió que se mostrara la salida correcta.
Ahora, si simplemente agrega un std::endl
al final del búfer, esto es lo que obtiene
int main() {
std::cout << "This text is quite nice and might as well be buffered" << std::endl;
raise(SIGSEGV); // Oh dear.. segmentation violation
std::cout << std::endl;
}
Salida:
This text is quite nice and might as well be buffered
bash: line 7: 22444 Segmentation fault (core dumped) ./a.out
Esta vez la salida es visible antes de la terminación del programa.
Las implicaciones de este hecho son múltiples. Puramente especulativo: si los datos estuvieran relacionados con un registro del servidor, su aplicación podría haberse bloqueado antes del registro real.
Recientemente he leído un artículo que dice que usar /n
es preferible a usar std::endl
porque endl
también descarga la secuencia.
Pero cuando busqué un poco más de información sobre el tema, encontré un sitio que decía:
Si se encuentra en una situación en la que debe evitar el almacenamiento en búfer, puede usar std :: endl en lugar de ''/ n''
Ahora viene mi pregunta: ¿En qué situación es preferible no escribir en el búfer? Porque solo vi ventajas de esa técnica. ¿No es también más seguro escribir en el búfer? Debido a que es más pequeño que un disco duro, se sobrescribirá más rápido que los datos almacenados en el HD (no estoy seguro de si esto es cierto).
Es preferible vaciar el búfer si necesita el destino de su flujo para recibir los datos antes de que se cierre el flujo.
Un ejemplo de la vida real sería un registro de aplicación, escrito desde un flujo que siempre está abierto ... Es posible que desee ver este registro mientras el programa aún se está ejecutando.
Espero que hayas perdido el enlace a ese sitio que encontraste. std::endl
no evita el almacenamiento en búfer. Se vacía lo que está en el búfer. Si necesita evitar el almacenamiento en búfer, use setf(ios_base::unitbuf)
. Eso establece que el flujo se vacíe después de cada inserción. Esa es la configuración predeterminada para std::clog
. La razón para hacer esto es que cuantas menos cosas se retengan en el búfer, mayor será la posibilidad de que los datos críticos se hayan escrito en el flujo cuando el programa falla.
El lavado también es importante para los programas interactivos: si escribe un mensaje en std::cout
, es bueno que ese mensaje aparezca en la pantalla antes de que el programa comience a esperar la entrada. Esto se hace automáticamente cuando usa std::cout
y std::cin
, a menos que se haya metido con la configuración de sincronización.
Muchos programadores parecen usar std::endl
como una forma elegante de deletrear ''/n''
, pero no lo es. No necesita vaciar el búfer de salida cada vez que escriba algo en él. Deja que el sistema operativo y la biblioteca estándar hagan su trabajo; se encargarán de llevar la salida al lugar adecuado de manera oportuna. Una simple std::cout << ''/n'';
es todo lo que se necesita para poner una nueva línea en la salida, y tarde o temprano, se mostrará en la pantalla. Si necesita que se muestre ahora, normalmente porque ha escrito toda la salida por el momento y no desea dejar la información mostrada incompleta, use std::endl
después de la última línea de la salida.
Primero, un poco de historia revisionista.
En los viejos tiempos, cuando todos usaban la biblioteca stdio.h
para hacer E / S, el texto que se veía de forma interactiva era típicamente con búfer de línea (o incluso sin búfer ), y el texto que no se encontraba en búfer . Por lo tanto, si envía ''/n''
al flujo, "siempre" hará lo correcto: las líneas que los usuarios buscaban se vaciaban y se veían de inmediato, y las líneas que se vuelcan al archivo se almacenan en búfer para obtener el máximo rendimiento.
Desafortunadamente, en realidad no siempre es lo correcto; el tiempo de ejecución no siempre puede predecir cómo los usuarios realmente desean ver el resultado de su programa. Una trampa común es redireccionar STDOUT
: la gente se acostumbra a ejecutar su programa en una consola y al ver el resultado (con su comportamiento de búfer de línea) en la consola, y luego, por cualquier motivo (por ejemplo, un trabajo de larga ejecución), deciden redirigir STDOUT
a un archivo, y se sorprenden rápidamente por el hecho de que la salida ya no está en el búfer de línea.
He visto semanas de supercomputadora desperdiciadas por esta razón; la salida era tan infrecuente que el búfer evitaba que alguien pudiera decir cómo estaba progresando el trabajo.
Sin embargo, la biblioteca iostream
C ++ fue diseñada para que sea más fácil hacer lo correcto aquí. Excepto cuando se sincroniza con stdio
, no hace esta cosa graciosa de "tal vez el búfer de línea tal vez el búfer completo". Siempre utiliza el almacenamiento en búfer completo (excepto cuando haces cosas sin buffer, por supuesto), y si quieres que las cosas se vacíen en una nueva línea, lo haces explícitamente .
Entonces, si está volcando un montón de texto con formato en un archivo que la gente no verá hasta que esté listo, usted escribe /n
para sus saltos de línea.
Pero si está escribiendo texto, es posible que la gente realmente quiera verlo mientras lo escribe, use std::endl
para sus saltos de línea y se mostrará de inmediato. Y si está escribiendo varias líneas a la vez, incluso puede hacerlo mejor: use ''/n''
para los saltos de línea intermedios y std::endl
para la última (o ''/n''
y std::flush
). Aunque en esta configuración, el rendimiento por lo general no importa, por lo que generalmente está bien usar std::endl
para todos los saltos de línea.
Será preferible en cualquier situación en la que desee que la salida aparezca exactamente cuando debía aparecer.
Un ejemplo simple:
#include <iostream>
int main() {
std::cout << "Please enter your name: " << std::endl;
std::string name;
std::cin >> name;
...
}
Con el almacenamiento en búfer, no aparecerá texto en la pantalla antes de que se espere que el usuario escriba su nombre, por lo que el usuario se confundirá. (Tenga en cuenta que, de hecho, puede ser realmente difícil o imposible lograr que este ejemplo se ejecute con el búfer completamente habilitado, ya que C ++ podría tomar medidas especiales para vaciar std::cout
antes de cualquier entrada de std::cin
, consulte ¿Por qué necesitamos un enlace? std :: cin and std :: cout?. Pero esto es solo un ejemplo teórico: en caso de que el búfer esté completamente habilitado, el usuario no verá el indicador.)
Tal situación puede ocurrir de vez en cuando, aunque puede que no sea muy frecuente. Considere escribir en una tubería para interactuar con otro proceso. O incluso si su programa escribe en el archivo de registro y usted mira personalmente el archivo de registro de vez en cuando para ver cómo se ejecuta --- en caso de almacenamiento en búfer, generalmente no verá la salida que se imprimió desde el programa, pero aún así Se mantiene en el búfer todavía.
Otra situación importante a tener en cuenta: si su programa falla severamente, es posible que el contenido del búfer no finalice en el disco duro. (Espero que los destructores de flujo descarguen el búfer, pero un bloqueo puede ser tan grave que no se llamará a ningún destructor).