HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

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行目の出力は、coutstdoutが同期されている状態なので、flushとかfflushをしなくても、それぞれに書き込んだ文字が交互に出力されることの確認。
  • 2行目の出力は、coutstdoutの同期を切っているので、末尾で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回目は、cincoutが結び付けられた状態なので、cinで読み込む前にcoutに書き込んだプロンプト("Enter name:")が画面に出てくることの確認。
  • 2回目は、cincoutの結びつきを切ってみたのだが、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回目のケースでプロンプトが先に出てくるということか。