Jakie jest znaczenie włączania
ios_base::sync_with_stdio(false);
cin.tie(NULL);
w programach C ++?
W moich testach przyspiesza to czas wykonania, ale czy istnieje przypadek testowy, o który powinienem się martwić, włączając go?
Czy te 2 stwierdzenia zawsze muszą być razem, czy też wystarczy pierwsze, tj. Ignorowanie cin.tie(NULL)
?
Ponadto, czy dozwolone jest używanie jednoczesnych poleceń C i C ++, jeśli jego wartość została ustawiona na false
?
https://www.codechef.com/viewsolution/7316085
Powyższy kod działał dobrze, dopóki nie użyłem scanf/printf
w programie C ++ z wartością as true
. W tym przypadku dało to błąd segmentacji. Jakie może być tego wytłumaczenie?
Odpowiedzi:
Te dwa wezwania mają różne znaczenia, które nie mają nic wspólnego z wydajnością; fakt, że przyspiesza czas wykonywania, jest (lub może być ) tylko efektem ubocznym. Powinieneś zrozumieć, co robi każdy z nich i nie włączać ich na ślepo do każdego programu, ponieważ wyglądają jak optymalizacja.
Spowoduje to wyłączenie synchronizacji między standardowymi strumieniami C i C ++. Domyślnie wszystkie standardowe strumienie są zsynchronizowane, co w praktyce pozwala na mieszanie I / O w stylu C i C ++ i uzyskanie rozsądnych i oczekiwanych rezultatów. Jeśli wyłączysz synchronizację, strumienie C ++ będą mogły mieć własne niezależne bufory, co sprawia, że mieszanie operacji we / wy w stylu C i C ++ jest przygodą.
Należy również pamiętać, że zsynchronizowane strumienie C ++ są bezpieczne dla wątków (dane wyjściowe z różnych wątków mogą się przeplatać, ale nie pojawiają się wyścigi danych).
To rozwiązuje
cin
zcout
. Powiązane strumienie zapewniają, że jeden strumień jest automatycznie opróżniany przed każdą operacją we / wy w drugim strumieniu.Domyślnie
cin
jest powiązany,cout
aby zapewnić rozsądną interakcję użytkownika. Na przykład:Jeśli
cin
icout
są powiązane, możesz oczekiwać, że dane wyjściowe zostaną opróżnione (tj. Będą widoczne na konsoli), zanim program poprosi użytkownika o dane wejściowe. Jeśli rozwiążesz strumienie, program może zablokować oczekiwanie na wprowadzenie przez użytkownika nazwy, ale komunikat „Wprowadź nazwę” nie jest jeszcze widoczny (ponieważcout
jest domyślnie buforowany, wyjście jest opróżniane / wyświetlane na konsoli tylko na żądanie lub gdy bufor jest pełny).Więc jeśli untie
cin
zcout
, należy upewnić się, aby opróżnićcout
ręcznie za każdym razem, gdy chcesz wyświetlić coś przed oczekując na wejściecin
.Podsumowując, wiedz, co robi każdy z nich, zrozum konsekwencje, a następnie zdecyduj, czy naprawdę chcesz lub potrzebujesz możliwego efektu ubocznego w postaci poprawy szybkości.
źródło
cout
jest buforowany z jakiegoś powodu, jeśli opróżniasz go zbyt często, gdy w rzeczywistości go nie potrzebujesz, możesz zobaczyć spadek wydajności.scanf()
, całkowicie wyłączyć buforowanie lub przełączyć się na buforowanie linii (które powinno opróżniać się po nowej linii lub po odczytaniu wejściastdin
- zobacz linux.die.net/man/3/setlinebuf ).Ma to na celu zsynchronizowanie operacji we / wy ze świata C i C ++. Jeśli zsynchronizujesz, masz gwarancję, że zamówienia we wszystkich zamówieniach reklamowych są dokładnie takie, jakich oczekujesz. Ogólnie problem polega na buforowaniu IO, które powoduje problem, synchronizacja pozwala obu światom na współużytkowanie tych samych buforów. Na przykład
cout << "Hello"; printf("World"); cout << "Ciao";
; bez synchronizacji nigdy nie dowiesz się,HelloCiaoWorld
czy otrzymasz,HelloWorldCiao
czyWorldHelloCiao
...tie
pozwala mieć gwarancję, że kanały IO w świecie C ++ są ze sobą powiązane , co oznacza na przykład, że każde wyjście zostało opróżnione przed pojawieniem się danych wejściowych (pomyśl ocout << "What's your name ?"; cin >> name;
).Zawsze możesz mieszać IO C lub C ++, ale jeśli chcesz rozsądnego zachowania, musisz zsynchronizować oba światy. Uważaj, generalnie nie zaleca się ich mieszania, jeśli programujesz w C używaj C stdio, a jeśli programujesz w C ++ używaj strumieni. Ale możesz chcieć wymieszać istniejące biblioteki C z kodem C ++, aw takim przypadku konieczne jest zsynchronizowanie obu.
źródło
cout <<
nie mogą zmienić kolejności, więcCiaoHelloWorld
nie jest to możliwe w Twoim przykładowym przypadku. Synchronizacja dotyczy wyłącznie różnych metod buforowania.Użycie
ios_base::sync_with_stdio(false);
jest wystarczające do oddzielenia strumieniC
iC++
. Możesz znaleźć dyskusję na ten temat w Standard C ++ IOStreams and Locales autorstwa Langera i Krefta. Zauważają, że sposób, w jaki to działa, jest określony przez implementację.cin.tie(NULL)
Rozmowa wydaje się zainteresowanie oddzielenia między działaniami nacin
icout
. Nie potrafię wyjaśnić, dlaczego użycie tego z inną optymalizacją powinno spowodować awarię. Jak wspomniano, podany link jest zły, więc nie ma tu żadnych spekulacji.źródło
To zwykła rzecz, dzięki której wejście cin działa szybciej.
Dla szybkiego wyjaśnienia: pierwsza linia wyłącza synchronizację bufora między strumieniem cin i narzędziami stdio w stylu C (takimi jak scanf lub gets) - więc cin działa szybciej, ale nie można go używać jednocześnie z narzędziami stdio .
Druga linia odłącza cin od cout - domyślnie bufor cout opróżnia się za każdym razem, gdy czytasz coś z cin . Może to być powolne, gdy wielokrotnie czytasz coś małego, a potem wielokrotnie piszesz coś małego. Tak więc linia wyłącza tę synchronizację (dosłownie wiążąc cin do null zamiast cout ).
źródło