C++の標準入出力についてのメモ
プログラミングコンテストなどでよく見かける以下のコード断片を「おまじない」で片づけるのが嫌だったので調べてみたメモ。
ios_base::sync_with_stdio(false); cin.tie(NULL);
答えは以下のサイトで解説されているのだが‥
試してみないと気が済まなかったので試してみた。
ios_base::sync_with_stdio(false)
の検証
以下のようなコードを実行してみる。
#include <cstdio> #include <iostream> using namespace std; void test1(int n, bool sync = false) { for (int i = 0; i < n; ++i) { cout << 'a'; if (sync) { flush(cout); } printf("A"); if (sync) { fflush(stdout); } } fflush(stdout); cout << endl; } int main(int argc, char* argv[]) { int n = 10; test1(n); ios_base::sync_with_stdio(false); test1(n); test1(n, true); }
これを実行すると、以下のような出力が得られる。
aAaAaAaAaAaAaAaAaAaA AAAAAAAAAAaaaaaaaaaa aAaAaAaAaAaAaAaAaAaA
- 1行目の出力は、
cout
とstdout
が同期されている状態なので、flush
とかfflush
をしなくても、それぞれに書き込んだ文字が交互に出力されることの確認。 - 2行目の出力は、
cout
とstdout
の同期を切っているので、末尾でfflush
を先にしているstdout
への出力が先にまとめて出てきて、その後にcout
への出力がまとめて出てくることの確認。 - 3行目の出力は、手動で同期をしているので、1行目と同じ出力になることの確認。
上記サイトの回答にあるように、これの副作用として標準出力への出力のパフォーマンスが上がるというわけか。
cin.tie(NULL)
の検証
以下のようなコードを実行してみる。
#include <iostream> using namespace std; void test2(bool tie = false) { string name; cout << "Enter name:"; if (tie) { flush(cout); } cin >> name; cout << name << endl; } int main(int argc, char* argv[]) { test2(); cin.tie(NULL); test2(); ios_base::sync_with_stdio(false); test2(); test2(true); }
これを実行し、4回の入力が求められるので、"A"、"B"、"C"、"D"を順にコンソールから入力した結果が以下。
Enter name:A A Enter name:B B C Enter name:C Enter name:D D
- 1回目は、
cin
とcout
が結び付けられた状態なので、cin
で読み込む前にcout
に書き込んだプロンプト("Enter name:")が画面に出てくることの確認。 - 2回目は、
cin
とcout
の結びつきを切ってみたのだが、1回目と出力が変わらなかった。 - 3回目は、ならば、と先に試した
ios_base::sync_with_stdio(false)
をやってみたらどうだろうと試した結果、今度は期待通りにcout
に書き込んだプロンプトが即座には出てこなかった。 - 4回目は、手動で
flush
しているので、1回目と同じ結果になることの確認。
cin.tie(NULL)
だけでは動作上の変化が無くて、ios_base::sync_with_stdio(false)
も合わせてしてやらないといけないらしい。cin
から読み込むときに、stdioとの同期が有効になっているとstdin
とも結びついていることになるから、同期しようとして2回目のケースでプロンプトが先に出てくるということか。