I'm not sure about how to use std::istream::exception
according to the standard, to let std::istream::operator>>
throw an exception if it can't read the input into a variable, e.g. double.
The following code has different behavior with clang/libc++ and gcc/libstdc++:
#include <iostream>
#include <cassert>
int main () {
double foo,bar;
std::istream& is = std::cin;
is.exceptions(std::istream::failbit);
is >> foo; //throws exception as expected with gcc/libstdc++ with input "ASD"
std::cout << foo;
is >> bar;
std::cout << bar;
assert(is); //failed with clang/libc++ after input "ASD"
std::cout << foo << " " << bar << std::endl;
}
Is is.exceptions(std::istream::failbit);
right for the purpose to let operator>>
throw, according to the C++ standard?
It seems that libc++ follows this requirement:
(quoted from N4567 § 27.7.2.2.1 [istream.formatted.reqmts] but the C++ IS contains identical wording. Emphasis mine)
I don't know whether this really implies "if
(exceptions()&badbit) == 0
then the input function shall not throw any exception", though.First some background information (each of these is explained below under it's respective title if you would like further elaboration):
istream
s to rethrow only whenios_base::badbit
is set inbasic_istream::exceptions
ios_base::badbit
bit-wise ored with the desiredios_base::iostate
as a workaroundUnfortunately this workaround has the side effect of also rethrowing whenever
ios_base::badbit
is set independent ofios_base::failbit
: http://en.cppreference.com/w/cpp/io/ios_base/iostate#The_badbitIf 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 theios_base::badbit
after each input operation occurring on theistream
. That'd need to look something like this:As noted by cpplearner you can't even use
basic_istream::fail
, you have to do a bit-wise test of theistream
'srdstate
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 theistream
could be combated by helper functions, but use ofistream_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 whenios_base::badbit
is set inbasic_istream::exceptions
Calling
basic_istream::exceptions(istream::failbit)
will set a mask which can be retrieved by callingbasic_istream::exceptions()
which according to 27.5.5.4 [iosstate.flags]/11 of the standard is:This is supported in 27.7.2.2.3 [istream::extractors]/15 for unformated insertion methods:
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:libstdc++ does not comply with this requirement but libc++ does
The
ios_base::failbit
should be set on it's respectiveistream
on events such as:[Source]
If only the
ios_base::failbit
is set on abasic_istream::exceptions
' mask and an event occurs, causing theios_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
libc++ proffers
ios_base::badbit
bit-wise ored with the desiredios_base::iostate
as a workaroundOur 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: