34078


2017-04-17-20:00

std::cerrについて調べていたところ以下のようなコード  
(<http://en.cppreference.com/w/cpp/io/cerr>)  
に行き当たったのですが、その挙動が理解できずに悩んでいます。

ソースコードは以下です。

[code]

    #include <thread>
    #include <iostream>
    #include <chrono>
    void f()
    {
        std::cout << "Output from thread...";
        std::this_thread::sleep_for(std::chrono::seconds(2));
        std::cout << "...thread calls flush()" << std::endl;
    }
    
    int main()
    {
        std::thread t1(f);
        std::this_thread::sleep_for(std::chrono::seconds(1));
        std::clog << "This output from main is not tie()'d to cout\n";
        std::cerr << "This output is tie()'d to cout\n";
        t1.join();
        return 0;
    }
    
[/code]

clang version 3.8.0-2ubuntu4
でコンパイルし、実際に手元の環境(Ubuntu16.04)で動かしてみた所出力は以下のようになりました。

[code]

    This output from main is not tie()'d to cout
    Output from thread...This output is tie()'d to cout
    ...thread calls flush()
    
[/code]

cerrはバッファリングを行わず、clogはバッファリングを行うとの認識だったのですが、この出力結果を見るに、clogへの出力はバッファリングされず、mainスレッドの待機命令を無視して真っ先に出力されているように見えます。また、その後に関数f()の一行目が実行され、t1スレッドも待機に入り、先に待機がとけたmainスレッドでcerrにバッファリングされていたメッセージが出力されているように見えます。  
何故このような挙動になり、僕の理解はどのように間違っているのでしょうか。  
どなたかご存じの方ご教授願います。

21:20  
質問投稿の後にも試行錯誤しつつ調べていたのですが、一部解決したのでここに報告させていただきます。  
"Output from thread..."よりも"Thid output
..."のほうが早く出力されていたのはf()内一行目ではflushが起きていないためでした。  
ここでバッファに溜まったテキストはcerrの手前で吐き出されていますが、これはcerrが呼び出し直後にまずcout.flushを呼び出すためのようです。以下参考URL  
(<http://en.cppreference.com/w/cpp/io/cerr>)

ただバッファリングされるはずのclogがそのまま出力されているのは未だ解決出来ていません。  
"\n"による行バッファリングの可能性も指摘していただいたのですが、"\n"を取り除いても出力は行われるのでこれが原因でもないようです。

21:43  
clogですが、試行錯誤の結果、既にcoutにバッファリングされているデータのflushは行わないものの、clog自体のflushはしているということがわかりました。「clogはバッファリングをする」という文言の意味を取り違えていたようです。問題解決に協力してくださったmetropolisさん、ありがとうございました。

21:55  
clogについてですが、  
cppreference.com（信用度が足りないらしくリンクが投稿できないので、サイト名だけで失礼します）  
には勝手にflushされない旨が書いてあるのでやはり不可解な挙動のようです。  
追加で調べて進展したらまた追記します。

04-18-12:45  
解決しました。詳しくはベストアンサーをご覧ください。Hidekiさんありがとうございました。


CC BY-SA 3.0
2017-04-17T10:41:20.867
34071
2017-04-18T03:46:05.227
2017-04-18T03:46:05.227
22606
22606
question
c++ c++11 stl
std::cerr,std::clogの違いについて


[isocpp.org](https://isocpp.org/) にある C++仕様のドラフト (n4618) を見てみましたが、std::clog
について書かれているのは、27.4.2 Narrow stream object の

> ostream cerr;  
>  The object cerr controls output to a stream buffer associated with the
> object stderr, declared in (27.11.1).  
>  After the object cerr is initialized, cerr.flags() & unitbuf is nonzero and
> cerr.tie() returns &cout. Its state is otherwise the same as required for
> basic_ios::init (27.5.5.2).
>
> ostream clog;  
>  The object clog controls output to a stream buffer associated with the
> object stderr, declared in (27.11.1).

と、27.5.3.1.6 Class ios_base::Init の

> Init();  
>  Effects: Constructs an object of class Init. Constructs and initializes the
> objects cin, cout, cerr, clog, wcin, wcout, wcerr, and wclog if they have
> not already been constructed and initialized.
>
> ~Init();  
>  Effects: Destroys an object of class Init. If there are no other instances
> of the class still in existence, calls cout.flush(), cerr.flush(),
> clog.flush(), wcout.flush(), wcerr.flush(), wclog.flush().

くらいで、他には見つかりませんでした。clog のバッファは、いつ flush されるか、どこにも記述がないので、実装依存と解釈するのが正しいと思います。

つまり

  * cerr については、少なくとも出力ごとには必ず flush される。
  * clog については、いつ flush されるか、わからない。出力ごとかもしれないし、あとで、まとめてかもしれない。

です。cppreference.com の記述は、ちょっと紛らわしいと思います。


CC BY-SA 3.0
2017-04-17T18:16:58.787
34078
2017-04-17T18:16:58.787
3605
34071
answer