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

144

Welche Bedeutung hat das Einbeziehen?

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

in C ++ - Programmen?

In meinen Tests wird die Ausführungszeit verkürzt. Gibt es jedoch einen Testfall, über den ich mir Sorgen machen sollte, wenn ich diesen einbeziehe?

Müssen die beiden Aussagen immer zusammen sein, oder reicht die erste aus, dh ignoriert cin.tie(NULL)?

Ist es auch zulässig, gleichzeitige C- und C ++ - Befehle zu verwenden, wenn der Wert auf festgelegt wurde false?

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

Der obige Code funktionierte einwandfrei, bis ich ihn scanf/printfin einem C ++ - Programm mit dem Wert as verwendete true. In diesem Fall gab es einen Segmentierungsfehler. Was könnte die mögliche Erklärung dafür sein?

Kshitij Kohli
quelle
Sie haben das tatsächlich mit false verwendet. Dein Code sagt es ???
Suraj Jain

Antworten:

228

Die beiden Aufrufe haben unterschiedliche Bedeutungen, die nichts mit der Leistung zu tun haben. Die Tatsache, dass es die Ausführungszeit beschleunigt, ist (oder könnte ) nur ein Nebeneffekt. Sie sollten verstehen, was jeder von ihnen tut, und sie nicht blind in jedes Programm aufnehmen, da sie wie eine Optimierung aussehen.

ios_base::sync_with_stdio(false);

Dies deaktiviert die Synchronisation zwischen den C- und C ++ - Standardströmen. Standardmäßig sind alle Standard-Streams synchronisiert, sodass Sie in der Praxis E / A im C- und C ++ - Stil mischen und vernünftige und erwartete Ergebnisse erzielen können. Wenn Sie die Synchronisation deaktivieren, dürfen C ++ - Streams ihre eigenen unabhängigen Puffer haben, was das Mischen von E / A im C- und C ++ - Stil zu einem Abenteuer macht.

Beachten Sie auch, dass synchronisierte C ++ - Streams threadsicher sind (die Ausgabe von verschiedenen Threads kann sich verschachteln, Sie erhalten jedoch keine Datenrennen).

cin.tie(NULL);

Dies löst sich cinvon cout. Gebundene Streams stellen sicher, dass ein Stream vor jeder E / A-Operation des anderen Streams automatisch gelöscht wird.

Standardmäßig cinist gebunden, coutum eine sinnvolle Benutzerinteraktion zu gewährleisten. Beispielsweise:

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

Wenn cinund coutgebunden sind, können Sie erwarten, dass die Ausgabe gelöscht wird (dh auf der Konsole sichtbar ist), bevor das Programm Eingaben vom Benutzer auffordert. Wenn Sie die Streams lösen, blockiert das Programm möglicherweise das Warten auf die Eingabe des Namens durch den Benutzer, aber die Meldung "Name eingeben" ist noch nicht sichtbar (da die coutAusgabe standardmäßig gepuffert ist, wird sie nur bei Bedarf oder wenn die Ausgabe auf der Konsole gelöscht / angezeigt Puffer ist voll).

Also , wenn Sie untie cinaus cout, müssen Sie sicherstellen, spülen coutmanuell jedes Mal , wenn Sie angezeigt werden, bevor sie auf erwartete Eingabe etwas wollen cin.

Wissen Sie abschließend, was jeder von ihnen tut, verstehen Sie die Konsequenzen und entscheiden Sie dann, ob Sie den möglichen Nebeneffekt einer Geschwindigkeitsverbesserung wirklich wollen oder brauchen .

Ionut
quelle
Wenn Sie sagen "Sie müssen sicherstellen, dass Sie cout jedes Mal manuell spülen, wenn Sie etwas anzeigen möchten, bevor Sie eine Eingabe auf cin erwarten", kann dies so einfach sein wie das Anhängen von "... << std :: flush" oder "... < <std :: endl "bis zum Ende jeder Zeile, die mit" std :: cout << ... "beginnt, richtig?
Alan
4
Ja, so einfach ist das, aber seien Sie vorsichtig mit dem Teil "Ende jeder Zeile". coutwird aus einem bestimmten Grund gepuffert. Wenn Sie es zu oft spülen und es nicht wirklich benötigen, wird möglicherweise ein Leistungseinbruch angezeigt.
Ionut
@Ionut gibt es etwas, das der tie () - Funktionalität in C für scanf, printf entspricht?
iajnr
1
@iajnr Nein, nicht direkt. In C können Sie entweder vorher manuell scanf()leeren, die Pufferung vollständig deaktivieren oder zur Zeilenpufferung wechseln (die nach dem Zeilenumbruch oder beim Lesen der Eingabe gelöscht werden sollte stdin- siehe linux.die.net/man/3/setlinebuf ).
Ionut
1
Bei leetcode wird die Laufzeit erheblich verbessert. Vielleicht bieten diese wettbewerbsfähigen Websites etwas Besonderes für Eingabetests.
P0W
17

Dies dient zum Synchronisieren von E / A aus der C- und C ++ - Welt. Wenn Sie synchronisieren, haben Sie die Garantie, dass die Reihenfolge aller E / A genau Ihren Erwartungen entspricht. Im Allgemeinen ist das Problem die Pufferung von E / A, die das Problem verursacht. Durch die Synchronisierung können beide Welten dieselben Puffer gemeinsam nutzen. Zum Beispiel cout << "Hello"; printf("World"); cout << "Ciao";; Ohne Synchronisation werden Sie nie wissen, ob Sie HelloCiaoWorldoder HelloWorldCiaooder WorldHelloCiao...

tiekönnen Sie die Garantie , dass IOs Kanäle in C ++ Welt sind gebunden zu einander, das heißt zum Beispiel , dass jeder Ausgang vor Eingänge (man denke etwa auftritt gespült wurden cout << "What's your name ?"; cin >> name;).

Sie können jederzeit C- oder C ++ - E / A-Vorgänge mischen. Wenn Sie jedoch ein angemessenes Verhalten wünschen, müssen Sie beide Welten synchronisieren. Beachten Sie, dass es im Allgemeinen nicht empfohlen wird, sie zu mischen, wenn Sie in C C stdio programmieren und wenn Sie in C ++ programmieren, Streams verwenden. Möglicherweise möchten Sie jedoch vorhandene C-Bibliotheken in C ++ - Code mischen. In diesem Fall müssen beide synchronisiert werden.

Jean-Baptiste Yunès
quelle
3
Auch ohne Synchronisation können verschiedene Aufrufe cout <<die Reihenfolge nicht ändern, sodass CiaoHelloWorlddies für Ihren Beispielfall nicht möglich ist. Bei der Synchronisation geht es ausschließlich um verschiedene Puffermethoden.
Mikko Rantalainen
3

Die Verwendung ios_base::sync_with_stdio(false);reicht aus, um die Cund C++Streams zu entkoppeln . Eine Diskussion hierzu finden Sie in Standard C ++ IOStreams and Locales von Langer und Kreft. Sie stellen fest, dass die Funktionsweise der Implementierung definiert ist.

Der cin.tie(NULL)Aufruf scheint eine Entkopplung zwischen den Aktivitäten auf cinund anzufordern cout. Ich kann nicht erklären, warum die Verwendung dieser Option mit der anderen Optimierung zu einem Absturz führen sollte. Wie bereits erwähnt, ist der von Ihnen angegebene Link schlecht, daher hier keine Spekulationen.

Don Wakefield
quelle
0

Es ist nur üblich, dass Cin- Eingaben schneller funktionieren.

Für eine kurze Erklärung: In der ersten Zeile wird die Puffersynchronisation zwischen dem Cin- Stream und den C-Style- Stdio- Tools (wie ScanF oder Gets) deaktiviert. Cin funktioniert also schneller, aber Sie können es nicht gleichzeitig mit Stdio- Tools verwenden.

In der zweiten Zeile wird cin von cout getrennt. Standardmäßig wird der cout- Puffer jedes Mal geleert, wenn Sie etwas von cin lesen . Und das kann langsam sein, wenn Sie wiederholt etwas Kleines lesen und dann mehrmals etwas Kleines schreiben. Die Zeile schaltet diese Synchronisation aus (indem cin buchstäblich mit null anstelle von cout verknüpft wird ).

Sravya
quelle