user1641854 user1641854 - 1 year ago 82
C++ Question

c++ std::ios_base::failure exception


) says ( Class ios_base::failure

The class failure defines the base class for the types of all objects
thrown as exceptions, by functions in the iostreams library, to report
errors detected during stream buffer operations.

I have a simple test program which emulates restricted resource environment while using of std::ostringstream:

#include <sys/time.h>
#include <sys/resource.h>

#include <errno.h>
#include <stdlib.h>
#include <string.h>

#include <iostream>
#include <sstream>

int main(int argc, const char* argv[])
rlimit limit;
limit.rlim_cur = limit.rlim_max = 268435456;

if(setrlimit(RLIMIT_AS, &limit)) {
std::cerr << "Cannot set resource limit: " << strerror(errno) << std::endl;

std::ostringstream os;

try {
auto iterations = 1024 * 1024 * 1024;

while(iterations && --iterations) os << 'F';

} catch(const std::ios_base::failure& ex) {
std::cerr << "Caught: std::ios_base::failure" << std::endl;
} catch(const std::bad_alloc& ex) {
std::cerr << "Caught: std::bad_alloc" << std::endl;
} catch(...) {
std::cerr << "Caught: ellipsis" << std::endl;

return 0;

In my environment (Linux, gcc 5.3.0) I got
Caught: std::bad_alloc
. One of online compilers shows the same output.

The question is: why exception type is
and not

Answer Source

os << 'F'; is operator<<(ostream&, char), which is a Formatted Output Function, and, quoting[ostream.formatted.reqmts],

the function endeavors to generate the requested output. If the generation fails, then the formatted output function does setstate(ios_base::failbit), which might throw an exception. If an exception is thrown during output, then ios::badbit is turned on without causing an ios::failure to be thrown. in *this’s error state. If (exceptions()&badbit) != 0 then the exception is rethrown

As part of output, this function calls stringbuf::overflow, which is specified, in[stringbuf.virtuals]p8, to perform reallocation. The difference between libstdc++ and libc++ here is the interpretation of the consequences of its allocation failure:

in libstdc++, it throws std::bad_alloc out of stringbuf::overflow, which unrolls the stack all the way to operator<< (technically, __ostream_insert), sets badbit and is rethrown, unmodified, as specified above.

In libc++, std::bad_alloc is caught inside stringbuf::overflow, and it makes overflow return traits::eof, which, in turn, makes the caller (in this case, steambuf::xsputn) return zero, which, in turn, makes the caller, __pad_and_output, wipe out the stream's rdbuf completely, which, in turn, makes its caller, __put_character_sequence, set both badbit and failbit. Setting of that badbit throws the ios::failure you caught.

Perhaps libc++ is technically correct in stringbuf::overflow: the standard says

''Returns:'' traits::eof() to indicate failure.

and it's hard to imagine a way for it to fail other than by allocation failure, but I think libstdc++'s interpretation is closer to the intent. (In libstdc++, stringbuf::overflow can still return eof, if the buffer capacity reaches string::max_size without first hitting bad_alloc)