The following deals only with iostreams and their buffer objects. For information about the buffers related to C-style I/O, please see @milleniumbug's answer.
Mostly because you (at least normally) want the stream's badbit set if attempting to flush the underlying buffer fails.
There's also a slightly complex little dance that streams use when interacting with the underlying stream, where the stream creates a sentry object, then carries out an action, then the sentry object is destroyed. The sentry is intended to make prefix and suffix operations exception safe.
So the overall sequence is something like this:
create sentry
if that succeeds (sentry converts to true) call rdbuf()->pubsync()
if that fails (returns -1) setstate(badbit);
A stream buffer (e.g., a basic_filebuf
) is directly attached to the underlying file system object--in fact, all the interaction between the iostream object and the underlying file object is done via the file buffer. As shown above, when the stream object does need to flush the buffer, all it needs to do it tell the buffer to flush itself by calling the buffer's pubsync()
member function.
[For reference: [ostream.unformatted]/7:
basic_ostream& flush();
Effects: Behaves as an unformatted output function (as described in 27.7.3.6.1, paragraph 1). If rdbuf() is not a null pointer, constructs a sentry object. If this object returns true when converted to a value of type bool the function calls rdbuf()->pubsync(). If that function returns -1 calls setstate(badbit) (which may throw ios_base::failure (27.5.5.4)). Otherwise, if the sentry object returns false, does nothing.
Returns: *this.
...and [ofstream.cons]/2:
explicit basic_ofstream(const char* s,
ios_base::openmode mode = ios_base::out);
Effects: Constructs an object of class basic_ofstream, initializing the base class with basic_ostream(&sb) and initializing sb with basic_filebuf()) (27.7.3.2, 27.9.1.2), then calls rdbuf()->open(s, mode|ios_base::out). If that function returns a null pointer, calls setstate(failbit).