First some background information (each of these is explained below under it's respective title if you would like further elaboration):
- The standard requires
istream
s to rethrow only when ios_base::badbit
is set in basic_istream::exceptions
- libstdc++ does not comply with this requirement but libc++ does
- libc++ invalidates bugs requesting it's mirroring of libstdc++ behavior
- libc++ proffers
ios_base::badbit
bit-wise ored with the desired ios_base::iostate
as a workaround
Unfortunately this workaround has the side effect of also rethrowing whenever ios_base::badbit
is set independent of ios_base::failbit
: http://en.cppreference.com/w/cpp/io/ios_base/iostate#The_badbit
If you're looking for a throw to happen only when ios_base::failbit
is set and you need this to have the same behavior on libc++ and libstdc++ you'll have to check the ios_base::badbit
after each input operation occurring on the istream
. That'd need to look something like this:
if((is.rdstate() & ios_base::failbit) != 0) throw ios_base::failure("basic_ios::clear");
As noted by cpplearner you can't even use basic_istream::fail
, you have to do a bit-wise test of the istream
's rdstate
return. But honestly that only adds a bit of complexity.
What could make this a monumental task is the extent to which the istream
is used. Wide usage of the istream
could be combated by helper functions, but use of istream_iterator
s or compound overloads of the extraction operator quickly make the manual inspection of this an unreasonable task.
If you find yourself there I would seriously consider the possibility of the is.exceptions(ios_base::failbit | ios_base::badbit)
workaround.
The standard requires istream
s to rethrow only when ios_base::badbit
is set in basic_istream::exceptions
Calling basic_istream::exceptions(istream::failbit)
will set a mask which can be retrieved by calling basic_istream::exceptions()
which according to 27.5.5.4 [iosstate.flags]/11 of the standard is:
A mask that determines what elements set in rdstate()
cause exceptions to be thrown.
This is supported in 27.7.2.2.3 [istream::extractors]/15 for unformated insertion methods:
If it inserted no characters because it caught an exception thrown while extracting characters from *this
and failbit
is on in exceptions()
(27.5.5.4), then the caught exception is rethrown.
However for formatted input this is retrograded in 27.7.2.2.1 [istream.formatted.reqmts]/1; requiring a throw to occur only when a bit-wise and of the mask and ios_base::badbit
is non-zero:
If an exception is thrown during input then ios::badbit
is turned on in *this
’s error state. If (exceptions()&badbit) != 0
then the exception is rethrown.
libstdc++ does not comply with this requirement but libc++ does
The ios_base::failbit
should be set on it's respective istream
on events such as:
The numeric, pointer, and boolean input overloads of basic_istream::operator>>
(technically, the overloads of num_get::get
they call), if the input cannot be parsed as a valid value or if the value parsed does not fit in the destination type.
[Source]
If only the ios_base::failbit
is set on a basic_istream::exceptions
' mask and an event occurs, causing the ios_base::failbit
to be set, such as extracting an invalid number as described above:
libc++ invalidates bugs requesting it's mirroring of libstdc++ behavior
There is a now invalidated bug against libc++ for this very issue. Citing 27.7.2.1 [istream]/4
If one of these called functions throws an exception, then unless explicitly noted otherwise, the input function sets badbit
in error state. If badbit
is on in exceptions()
, the input function rethrows the exception without completing its actions, otherwise it does not throw anything and proceeds as if the called function had returned a failure indication.
libc++ proffers ios_base::badbit
bit-wise ored with the desired ios_base::iostate
as a workaround
Our own Howard Hinnant (who also happens to be libc++'s representative who invalidated the linked libc++ bug) suggests in answer to a duplicate of this question (as well as in the libc++ bug) that you use the workaround:
is.exceptions(ios_base::failbit | ios_base::badbit);