Importancia de ios_base :: sync_with_stdio (falso); cin.tie (NULL);

146

¿Cuál es el significado de incluir

ios_base::sync_with_stdio(false);
cin.tie(NULL);

en programas C ++?

En mis pruebas, acelera el tiempo de ejecución, pero ¿hay algún caso de prueba que deba preocuparme al incluir esto?

¿Las dos afirmaciones siempre tienen que estar juntas, o es la primera suficiente, es decir, ignorar cin.tie(NULL)?

Además, ¿está permitido usar comandos simultáneos C y C ++ si su valor se ha establecido en false?

https://www.codechef.com/viewsolution/7316085

El código anterior funcionó bien, hasta que lo usé scanf/printfen un programa C ++ con el valor como true. En este caso, dio una falla de segmentación. ¿Cuál podría ser la posible explicación para esto?

Kshitij Kohli
fuente
En realidad lo usaste con falso. Tu código lo dice ???
Suraj Jain

Respuestas:

231

Las dos llamadas tienen significados diferentes que no tienen nada que ver con el rendimiento; El hecho de que acelere el tiempo de ejecución es (o podría ser ) solo un efecto secundario. Debe comprender lo que hace cada uno de ellos y no incluirlos a ciegas en todos los programas porque parecen una optimización.

ios_base::sync_with_stdio(false);

Esto deshabilita la sincronización entre las secuencias estándar C y C ++. Por defecto, todas las transmisiones estándar están sincronizadas, lo que en la práctica le permite mezclar E / S de estilo C y C ++ y obtener resultados sensibles y esperados. Si deshabilita la sincronización, las transmisiones de C ++ pueden tener sus propios buffers independientes, lo que hace que la mezcla de E / S al estilo C y C ++ sea una aventura.

También tenga en cuenta que las secuencias sincronizadas de C ++ son seguras para subprocesos (la salida de diferentes subprocesos puede intercalarse, pero no obtiene carreras de datos).

cin.tie(NULL);

Esto se desata cinde cout. Las secuencias vinculadas aseguran que una secuencia se vacíe automáticamente antes de cada operación de E / S en la otra secuencia.

Por defecto cinestá vinculado a coutgarantizar una interacción sensible del usuario. Por ejemplo:

std::cout << "Enter name:";
std::cin >> name;

Si ciny coutestán vinculados, puede esperar que la salida se vacíe (es decir, sea visible en la consola) antes de que el programa solicite la entrada del usuario. Si desata las transmisiones, el programa puede bloquear la espera de que el usuario ingrese su nombre, pero el mensaje "Ingresar nombre" aún no está visible (porque coutestá almacenado de forma predeterminada, la salida se vacía / muestra en la consola solo a pedido o cuando el el búfer está lleno).

Así que si desatar cina partir cout, debe asegurarse para eliminar coutmanualmente cada vez que desea mostrar algo antes de esperar la entrada en cin.

En conclusión, sepa qué hace cada uno de ellos, comprenda las consecuencias y luego decida si realmente quiere o necesita el posible efecto secundario de la mejora de la velocidad.

Ionut
fuente
Cuando dice "debe asegurarse de enjuagar cout manualmente cada vez que desee mostrar algo antes de esperar la entrada en cin", eso puede ser tan simple como agregar "... << std :: flush" o "... < <std :: endl "al final de cada línea que comienza" std :: cout << ... ", ¿verdad?
Alan
44
Sí, es tan simple como eso, pero tenga cuidado con la parte "al final de cada línea". coutestá almacenado en un búfer por una razón, si lo descarga con demasiada frecuencia, cuando realmente no lo necesita, es posible que vea un impacto en el rendimiento.
Ionut
@Ionut ¿hay algo equivalente a la funcionalidad tie () en C para scanf, printf?
iajnr
1
@iajnr No, no directamente. En C, puede enjuagar manualmente antes scanf(), deshabilitar el almacenamiento en búfer por completo o cambiar al almacenamiento en línea (que debe enjuagarse después de la nueva línea o cuando se lee la entrada stdin; consulte linux.die.net/man/3/setlinebuf ).
Ionut
1
En leetcode, mejora significativamente el tiempo de ejecución, tal vez estos sitios web competitivos hacen algo especial para las pruebas de entrada.
P0W
17

Esto es para sincronizar las E / S del mundo C y C ++. Si sincroniza, tiene la garantía de que las órdenes de todos los IO son exactamente lo que espera. En general, el problema es el almacenamiento en búfer de E / S que causa el problema, la sincronización permite que ambos mundos compartan los mismos almacenamientos intermedios. Por ejemplo cout << "Hello"; printf("World"); cout << "Ciao";; sin sincronización nunca sabrá si obtendrá HelloCiaoWorldo HelloWorldCiaoo WorldHelloCiao...

tiele permite tener la garantía de que los canales de E / S en el mundo de C ++ están vinculados entre sí, lo que significa, por ejemplo, que cada salida se ha vaciado antes de que ocurran las entradas (piense cout << "What's your name ?"; cin >> name;).

Siempre puede mezclar E / S C o C ++, pero si desea un comportamiento razonable, debe sincronizar ambos mundos. Tenga en cuenta que en general no se recomienda mezclarlos, si programa en C use C stdio, y si programa en C ++ use streams. Pero es posible que desee mezclar bibliotecas C existentes en código C ++, y en tal caso es necesario sincronizar ambas.

Jean-Baptiste Yunès
fuente
3
Incluso sin sincronización, diferentes llamadas a cout <<no pueden cambiar el orden, por CiaoHelloWorldlo que no es posible para su caso de ejemplo. La sincronización se trata estrictamente de diferentes métodos de almacenamiento en búfer.
Mikko Rantalainen
3

El uso ios_base::sync_with_stdio(false);es suficiente para desacoplar las secuencias Cy C++. Puede encontrar una discusión sobre esto en Standard C ++ IOStreams and Locales , de Langer y Kreft. Señalan que su funcionamiento está definido por la implementación.

La cin.tie(NULL)llamada parece estar solicitando un desacoplamiento entre las actividades en ciny cout. No puedo explicar por qué usar esto con la otra optimización debería causar un bloqueo. Como se señaló, el enlace que proporcionó es malo, por lo que no hay especulaciones aquí.

Don Wakefield
fuente
0

Es solo algo común para hacer que la entrada cin funcione más rápido.

Para una explicación rápida: la primera línea desactiva la sincronización del búfer entre el flujo cin y las herramientas stdio de estilo C (como scanf o gets), por lo que cin funciona más rápido, pero no puede usarlo simultáneamente con las herramientas stdio .

La segunda línea desata cin de cout : de forma predeterminada, el búfer de cout se vacía cada vez que lee algo de cin . Y eso puede ser lento cuando lees repetidamente algo pequeño y luego escribes algo pequeño muchas veces. Entonces, la línea apaga esta sincronización (al vincular literalmente cin a nulo en lugar de cout ).

Sravya
fuente