I'm trying to learn a bit more about how I/O streams work in C++, and I'm really confused at when to use what.
What exactly is a streambuf
?
When do I use a streambuf
, as compared to a string
, an istream
, or a vector
? (I already know the last three, but not how streambuf
compares to them, if it does at all.)
Stream buffers represent input or output devices and provide a low level interface for unformatted I/O to that device. Streams, on the other hand, provide a higher level wrapper around the buffer by way of basic unformatted I/O functions and especially via formatted I/O functions (i.e., operator<<
and operator>>
overloads). Stream objects may also manage a stream buffer's lifetime.
For example a file stream has an internal file stream buffer. The stream manages the lifetime of the buffer and the buffer is what provides actual read and write capabilities to a file. The stream's formatting operators ultimately access the stream buffer's unformatted I/O functions, so you only ever have to use the stream's I/O functions, and don't need to touch the buffer's I/O functions directly.
Another way to understand the differences is to look at the different uses they make of locale objects. Streams use the facets that have to do with formatting such as numpunct
and num_get
. You can also expect that the overloads of stream operator<<
and operator>>
for custom time or money data types will use the time and money formatting facets. Stream buffers, however, use the codecvt facets in order to convert between the units their interface uses and bytes. So, for example, the interface for basic_streambuf<char16_t>
uses char16_t
and so basic_streambuf<char16_t>
internally uses codecvt<char16_t, char, mbstate_t>
by default to convert the formatted char16_t
units written to the buffer to char
units written to the underlying device. So you can see that streams are mostly for formatting and stream buffers provide a low level interface for unformatted input or output to devices which may use a different, external encoding.
You can use a stream buffer when you want only unformatted access to an I/O device. You can also use stream buffers if you want to set up multiple streams that share a stream buffer (though you'll have to carefully manage the lifetime of the buffer). There are also special purpose stream buffers you might want to use, such as wbuffer_convert
in C++11 which acts as a façade for a basic_streambuf<char>
to make it look like a wide character stream buffer. It uses the codecvt facet it's constructed with instead of using the codecvt facet attached to any locale. You can usually achieve the same effect by simply using a wide stream buffer imbued with a locale that has the appropriate facet.