ios_base::sync_with_stdio(false); cin.tie(0); の意味


このエントリーをはてなブックマークに追加

競技プログラミングC++を使うときに、入出力を高速化する目的でおまじないのように書かれる

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

の意味、実はよくわかっていなかったので c++ - Significance of ios_base::sync_with_stdio(false); cin.tie(NULL); - Stack Overflow を主に参考として調べてみました。

sync_with_stdio(false);

C++の標準入出力ストリームがCの入出力と同期しないようにします。代償として、 std::cinscanf() を混ぜたり std::coutprintf() を混ぜたりすると破滅するようになります。

std::cinscanf()を混ぜて入力がおかしくなる例を示します。まず以下のようなテキストファイルを用意します。

100
0 1 2 3 (略) 98 99

これを、以下のようにstd::ios::sync_with_stdio(false); した上で、std::cinscanf()で交互に数値を読み込みます。

#include <iostream>
#include <cstdio>
#include <vector>

int main(void)
{
    // C++の標準入出力ストリームがCの入出力と同期しないようにする
    std::ios::sync_with_stdio(false);

    int N;
    std::cin >> N;

    // 標準入力からcinとscanfで交互に数字を読む
    std::vector<int> arr(N);
    for(int n = 0; n < N; ++n) {
        if (n % 2) std::cin >> arr[n];
        else scanf("%d", &arr[n]);
    }

    // 読み取った結果を表示
    for(int n = 0; n < N; ++n) {
        std::cout << arr[n] << " ";
    }
    std::cout << std::endl;

    return 0;
}

出力例は以下です。正しく数値を読み込めていないことがわかります。

0 0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0 12 0 13 0 14 0 15 0 16 0 17 0 18 0 19 0 20 0 21 0 22 0 23 0 24 0 25 0 26 0 27 0 28 0 29 0 30 0 31 0 32 0 33 0 34 0 35 0 36 0 37 0 38 0 39 0 40 0 41 0 42 0 43 0 44 0 45 0 46 0 47 0 48 0 49

コードは https://ideone.com/u6TBWZ で実行を試すことができます。

cin.tie(0)

std::cinstd::coutとの結合を解きます。例えば、std::coutで出力を要求する文字が全部出力される前に、std::cinによる入力待ち状態になることがありえるようになります。

#include <iostream>
int main(void)
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);

    int n;
    for(int rep = 0; rep < 3; ++rep) {
        std::cout << "Input number: ";
        std::cin >> n;
        std::cout << n << " is given." << std::endl;
    }

    return 0;
}

実行例は以下です。Input number: が表示される前に数値の入力が要求されてしまいました。

$ ./a.exe
100
Input number: 100 is given.
200
Input number: 200 is given.
300
Input number: 300 is given.

std::cout << "Input number: " << std::flush; とすればこの問題は解決可能です。