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

147

Quelle est l'importance d'inclure

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

dans les programmes C ++?

Dans mes tests, cela accélère le temps d'exécution, mais y a-t-il un cas de test dont je devrais m'inquiéter en l'incluant?

Les 2 déclarations doivent-elles toujours être ensemble, ou la première est-elle suffisante, c'est-à-dire ignorée cin.tie(NULL)?

De plus, est-il permis d'utiliser des commandes C et C ++ simultanées si sa valeur a été définie sur false?

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

Le code ci-dessus fonctionnait bien, jusqu'à ce que je l'utilise scanf/printfdans un programme C ++ avec la valeur comme true. Dans ce cas, il a donné un défaut de segmentation. Quelle pourrait en être l'explication possible?

Kshitij Kohli
la source
Vous avez en fait utilisé cela avec false. Votre code le dit ???
Suraj Jain

Réponses:

233

Les deux appels ont des significations différentes qui n'ont rien à voir avec la performance; le fait qu'il accélère le temps d'exécution n'est (ou pourrait être ) qu'un effet secondaire. Vous devez comprendre ce que chacun d'eux fait et ne pas les inclure aveuglément dans chaque programme car ils ressemblent à une optimisation.

ios_base::sync_with_stdio(false);

Cela désactive la synchronisation entre les flux standard C et C ++. Par défaut, tous les flux standard sont synchronisés, ce qui vous permet en pratique de mélanger les E / S de style C et C ++ et d'obtenir des résultats raisonnables et attendus. Si vous désactivez la synchronisation, les flux C ++ sont autorisés à avoir leurs propres tampons indépendants, ce qui fait du mélange d'E / S de style C et C ++ une aventure.

Gardez également à l'esprit que les flux C ++ synchronisés sont thread-safe (la sortie de différents threads peut s'entrelacer, mais vous n'obtenez aucune course de données).

cin.tie(NULL);

Cette délie cindecout . Les flux liés garantissent qu'un flux est automatiquement vidé avant chaque opération d'E / S sur l'autre flux.

Par défaut, cinest lié à coutpour assurer une interaction utilisateur sensible. Par exemple:

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

Si cinet coutsont liés, vous pouvez vous attendre à ce que la sortie soit vidée (c'est-à-dire visible sur la console) avant que le programme ne demande l'entrée de l'utilisateur. Si vous détachez les flux, le programme peut bloquer l'attente que l'utilisateur entre son nom, mais le message "Entrer le nom" n'est pas encore visible (car il coutest mis en mémoire tampon par défaut, la sortie est purgée / affichée sur la console uniquement à la demande ou lorsque le la mémoire tampon est pleine).

Donc, si vous détachez cinde cout, vous devez vous assurer de vider coutmanuellement chaque fois que vous souhaitez afficher quelque chose avant d'attendre une entrée cin.

En conclusion, sachez ce que chacun d'eux fait, comprenez les conséquences, puis décidez si vous voulez vraiment ou avez besoin de l' effet secondaire possible de l'amélioration de la vitesse.

Ionut
la source
Quand vous dites "vous devez vous assurer de vider cout manuellement chaque fois que vous voulez afficher quelque chose avant d'attendre une entrée sur cin", cela peut être aussi simple que d'ajouter "... << std :: flush" ou "... < <std :: endl "à la fin de chaque ligne qui commence" std :: cout << ... ", non?
Alan
4
Oui, c'est aussi simple que cela, mais soyez prudent avec la partie "fin de chaque ligne". coutest mis en mémoire tampon pour une raison, si vous le videz trop souvent, lorsque vous n'en avez pas réellement besoin, vous risquez de voir un impact négatif sur les performances.
Ionut
@Ionut y a-t-il quelque chose d'équivalent à la fonctionnalité tie () en C pour scanf, printf?
iajnr
1
@iajnr Non, pas directement. En C, vous pouvez soit vider manuellement avant scanf(), désactiver complètement la mise en mémoire tampon, soit passer à la mise en mémoire tampon de ligne (qui devrait vider après une nouvelle ligne ou lorsque l'entrée est lue depuis stdin- voir linux.die.net/man/3/setlinebuf ).
Ionut
1
Chez leetcode, cela améliore considérablement l'exécution, peut-être que ces sites Web concurrents font quelque chose de spécial pour les tests d'entrée.
P0W
18

Il s'agit de synchroniser les E / S du monde C et C ++. Si vous synchronisez, vous avez la garantie que les commandes de tous les E / S correspondent exactement à ce que vous attendez. En général, le problème est la mise en mémoire tampon des E / S qui cause le problème, la synchronisation permet aux deux mondes de partager les mêmes tampons. Par exemple cout << "Hello"; printf("World"); cout << "Ciao";; sans synchronisation, vous ne saurez jamais si vous obtiendrez HelloCiaoWorldou HelloWorldCiaoou WorldHelloCiao...

tievous permet d'avoir la garantie que les canaux d'E / S dans le monde C ++ sont liés les uns aux autres, ce qui signifie par exemple que chaque sortie a été vidée avant que les entrées ne se produisent (pensez à cout << "What's your name ?"; cin >> name;).

Vous pouvez toujours mélanger des E / S C ou C ++, mais si vous voulez un comportement raisonnable, vous devez synchroniser les deux mondes. Attention, en général, il n'est pas recommandé de les mélanger, si vous programmez en C utilisez C stdio, et si vous programmez en C ++ utilisez des flux. Mais vous voudrez peut-être mélanger les bibliothèques C existantes dans du code C ++, et dans ce cas, il est nécessaire de synchroniser les deux.

Jean-Baptiste Yunès
la source
4
Même sans synchronisation, différents appels à cout <<ne peuvent pas changer l'ordre, ce CiaoHelloWorldn'est donc pas possible pour votre exemple de cas. La synchronisation concerne strictement différentes méthodes de mise en mémoire tampon.
Mikko Rantalainen
3

L'utilisation ios_base::sync_with_stdio(false);est suffisante pour découpler les flux Cet C++. Vous pouvez trouver une discussion à ce sujet dans les IOStreams et les paramètres régionaux C ++ standard , par Langer et Kreft. Ils notent que la façon dont cela fonctionne est définie par l'implémentation.

le cin.tie(NULL) appel semble demander un découplage entre les activités sur cinet cout. Je ne peux pas expliquer pourquoi l'utilisation de ceci avec l'autre optimisation devrait provoquer un crash. Comme indiqué, le lien que vous avez fourni est mauvais, donc pas de spéculation ici.

Don Wakefield
la source
0

C'est juste des trucs communs pour faire du cin accélérer le travail de l'entrée .

Pour une explication rapide: la première ligne désactive la synchronisation de la mémoire tampon entre le flux cin et les outils stdio de style C (comme scanf ou gets) - donc cin fonctionne plus rapidement, mais vous ne pouvez pas l'utiliser simultanément avec stdio outils .

La deuxième ligne délie cin de cout - par défaut, le tampon cout se vide chaque fois que vous lisez quelque chose depuis cin . Et cela peut être lent lorsque vous lisez à plusieurs reprises quelque chose de petit, puis écrivez quelque chose de petit plusieurs fois. Ainsi, la ligne désactive cette synchronisation (en liant littéralement cin à null au lieu de cout ).

Sravya
la source