7
#include <iostream>
using std::cout;
using std::endl;
using std::cerr;
#include <cstdio>

int   main( )
{
    char pbuffer[BUFSIZ];
    setbuf(stdout, pbuffer);
    cout << "hello cout" ;
    sleep(5);
    cerr << "hello cerr";
    sleep(5);
    cout << "\nAll   done " << endl;
    sleep(5);
    return 0;
}

after I compile and run the program above, it's output is :

hello couthello cerr
All   done 

but I think it should be:

hello cerrhello cout
All   done 

I want to know, why cerr flushes the buffer of cout ?

Ben Jackson
  • 90,079
  • 9
  • 98
  • 150
wildpointercs
  • 141
  • 1
  • 7

2 Answers2

11

This is by design.

Both cin and cerr are tied to cout, and calls cout.flush() before any of their own operations.

The idea is probably that input and output should occur in a proper order.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • This is wrong. `cout` is tied to `cin`, but that's all. `cerr` isn't tied to anything, and has nothing tied to it. (That doesn't mean that the implementation isn't using other synchronization mechanisms. But `cerr.tie()` is required to return a null pointer.) – James Kanze May 17 '11 at 08:12
  • A quick check shows that VC8 has an error here: `cerr.tie()` does return non-null, even though this is explicitly forbidden by the C++ standard. (g++ gets it right.) – James Kanze May 17 '11 at 08:16
  • @James - In my copy of the draft is says "After the object cerr is initialized, `cerr.flags() & unitbuf` is nonzero and `cerr.tie()` returns `&cout`." (27.4.2) – Bo Persson May 17 '11 at 08:18
  • I'm looking at the actual ISO C++ 2003 standard, which says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for `basic_ios::init.", which requires `tie() == 0`. I see that later drafts have changed this---yet another incompatibility to deal with. (Not a serious one, however, since as far as I can see, `cout` and `cerr` could actually share the same `streambuf`, which synchronizes even more.) – James Kanze May 17 '11 at 08:31
  • 1
    `cerr` is _now_ tied to `cout` - citing https://en.cppreference.com/w/cpp/io/cerr - In addition, `std::cerr.tie()` returns `&std::cout` (same for` wcerr` and `std::wcout`), meaning that any output operation on `std::cerr` first executes `std::cout.flush()` (via `std::basic_ostream::sentry`'s constructor) (since C++11). – aafulei Jan 19 '22 at 05:08
  • For historical interests: the request of the behavior change to make `cerr` tie to `cout` was once rejected by the committee in [LWG 178](https://wg21.link/lwg178), but later [WG21 N1569](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1569.htm) pointed out it should be changed. Then came [LWG 455](https://wg21.link/lwg455). Finally the fix was adopted [in the working paper](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1805.html) in 2005. – FrankHB Mar 05 '23 at 20:59
10

First, a stream is allowed to flush whenever it feels like it. I possible that some implementations of iostream do change buffering policies when outputting to an interactive device. Unless you intentionally flush between outputs on the two streams, the order they appear is more or less unspecified; all you can count on is that a single << to cerr will not have characters from cout inserted into it. In your case, the implementation is synchronizing cout and cerr in some way. (You might want to see what happens if you redirect their output to different files. Or to the same non-interactive file—C++ makes no distinction between interactive devices and others, but C does, and I expect that most C++ implementations follow C in this respect.)

FWIW, the two guarantees concerning order are:

  • cout is tied to cin, so any attempt to read on cin will flush cout, and
  • cerr has unitbuf set, so it will be flushed at the end of every << operator.

The idea behind the latter is, I think, to obtain something similar to C's line buffering, which C++ doesn't support directly—although if you use std::endl, you get the same effect as line buffering.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
James Kanze
  • 150,581
  • 18
  • 184
  • 329