10

While libstdc++ does not, libc++ does followthe standard which states that passingios_base::failbit tobasic_istream::exceptions has no effect on formatted input. For example this code:

istringstream is{"ASD"};    double foo;is.exceptions(istream::failbit);try {    is >> foo;    cout << foo << endl;} catch(ios_base::failure& fail) {    cout << "ouch\n";}

Would result in:

My reading ofLWG2349 is that it would causebasic_istream to not throw on any formatted input.

For example LWG2349 proposes a change to the standard's 27.7.2.3 [istream]/1 which was cited with reference tothe invalidation of a bug that would have made libc++ behave like libstdc++. The change is in bold and strike through below:

If an exception, other than the ones thrown fromclear(), if any, is thrown during input thenios::badbit is turned on in*this’s error state.(Exceptions thrown frombasic_ios<>::clear() are not caught or rethrown.) If(exceptions()&badbit) != 0 then the exception is rethrown.

I understand thatbasic_istream::clear is what throws in reaction to bad formatted input so am I misreading LWG2349 or is it in fact going to stopbasic_istream from throwing any errors?

askedJan 29, 2016 at 16:01
Jonathan Mee's user avatar

1 Answer1

9

The point of the language excluding exceptions "thrown fromclear()" is to ensure thatifclear() throws, because an input function has calledclear(failbit)and(exceptions() & failbit) != 0, then badbit is not set as a result.clear() will continue to throw in that case, it just will not set badbit.

As described in the commentary to LWG2349, the intention is that badbit is set when an exception is thrown from user code:

PJ and Matt both agree that the intention (of badbit + rethrow) is "to signify an exception arising in user code, not the iostreams package".

Now, when can an exception be thrown by "user code" but within the iostreams machinery? One example would be by the locale getters:

struct my_get : std::num_get<char> {    using iter_type = std::istreambuf_iterator<char>;    iter_type do_get(iter_type, iter_type, std::ios_base&, std::ios_base::iostate&, bool&) const override {        throw std::logic_error{"my_get::do_get"};    }};int main() {    std::istringstream iss;    iss.imbue({std::locale{}, new my_get});    iss.exceptions(std::ios_base::failbit | std::ios_base::badbit);    try {        bool b;        iss >> b;    } catch (std::exception& ex) {        std::cout << ex.what() << '\n';    }    std::cout        << ((iss.rdstate() & std::ios_base::eofbit) ? "eof " : "")        << ((iss.rdstate() & std::ios_base::failbit) ? "fail " : "")        << ((iss.rdstate() & std::ios_base::badbit) ? "bad " : "")        << '\n';}

At present, gcc outputs:

eof fail

clang outputs:

eof fail

After LWG2349, the correct behavior is to set badbit and rethrow the exception:

my_get::do_geteof bad
answeredJan 29, 2016 at 16:54
ecatmur's user avatar
Sign up to request clarification or add additional context in comments.

15 Comments

Your 2nd sentence says: "clear() will continue to throw in that case, it just will not setbadbit." And that throw would stillnot be rethrown, if theexceptions() & ios_base::badbit == 0, right? So this won't do anything to align the question's example behaviors of libc++ and libstdc++?
@JonathanMee the intention is that the throw fromclear() is not caught (or, if it is caught, it is invisibly rethrown without settingbadbit); the catch and rethrow only applies to user-thrown exceptions. So in the question's example, the correct output would be "ouch".
@JonathanMee it helps to be aware of e.g. 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." The purpose of LWG2349 is to ensure that user-thrown exceptions from other user code (not justsbumpc andsgetc) behave similarly.
@JonathanMee That particular change was apparently intended to be stylistic - the discussion section says that the previous version with the parenthetical "lost some context (the word "rethrown" is not seen before this sentence within this section)". Again, at this point, one should focus on the intent, not the exact proposed wording.
@JonathanMee yes, definitely. I think a small part of the problem is that throwing theclear exception "all the way" is not actually possible - a conformant implementation would have to wrap user operations in a try block, so would have to specifically catchios_base::failure and rethrow it withthrow;. But that's an implementation detail - it should indeed appear to the user as if theios_base::failure thrown byclear is thrown all the way.
|

Your Answer

Sign up orlog in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

By clicking “Post Your Answer”, you agree to ourterms of service and acknowledge you have read ourprivacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.