Consider the following code snippet:
std::stringstream ss;
ss << "hello world!\n";
auto a = ss.rdbuf();
std::cout << a; // prints out "hello world!
The variable a
is a pointer to an object of the type std::stringbuf
. When it is passed to the stream output operator <<
, with GCC9.4, the content of the stream buffer pointed by a
gets printed out.
My question is: is this behavior just an accident from the way std::stringbuf
is implemented in GCC, or does the language standard guarantee this will always work?
A std::basic_stringbuf
is derived from a std::basic_streambuf. Cppreference describes its use:
The I/O stream objects
std::basic_istream
andstd::basic_ostream
, as well as all objects derived from them (std::ofstream
,std::stringstream
, etc), are implemented entirely in terms ofstd::basic_streambuf
.
What does that mean? Well, let's take a look at the overload set for std::basic_istream::operator<<
here:
basic_ostream& operator<<( std::basic_streambuf<CharT, Traits>* sb );
(10)
Behaves as an
UnformattedOutputFunction
. After constructing and checking the sentry object, checks ifsb
is a null pointer. If it is, executessetstate(badbit)
and exits. Otherwise, extracts characters from the input sequence controlled bysb
and inserts them into*this
until one of the following conditions are met:
- end-of-file occurs on the input sequence;
- inserting in the output sequence fails (in which case the character to be inserted is not extracted);
- an exception occurs (in which case the exception is caught).
If no characters were inserted, executes
setstate(failbit)
. If an exception was thrown while extracting, setsfailbit
and, iffailbit
is set inexceptions()
, rethrows the exception.
So, yes, it's guaranteed by the standard that std::cout << ss.rdbuf();
will have the effect you observed.