2349. Clarify input/output function rethrow behavior

Section: 31.7.5.3.1 [istream.formatted.reqmts] Status: Resolved Submitter: Zhihao Yuan Opened: 2013-12-06 Last modified: 2022-11-22

Priority: 3

View all other issues in [istream.formatted.reqmts].

View all issues with Resolved status.

Discussion:

The formatted input function requirement says in 31.7.5.3.1 [istream.formatted.reqmts]:

"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."

while some formatted function may throw an exception from basic_ios::clear, for example in 22.9.4 [bitset.operators] p6:

"If no characters are stored in str, calls is.setstate(ios_base::failbit) (which may throw ios_base::failure)"

So should this exception be considered as "an exception [...] thrown during input"? And here is an implementation divergence (or you can read the following as "a bug libc++ only has" :)

cin.exceptions(ios_base::failbit);
bitset<N> b;
try {
  cin >> b;  // type 'a' and return
} catch (...)
{}

Now cin.rdstate() is just failbit in libstdc++ (and Dinkumware, by PJ), but failbit & badbit libc++. Similar difference found in other places, like eofbit & badbid after std::getline.

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

In addition, I found the following words in unformatted input function's requirements (31.7.5.4 [istream.unformatted]):

If an exception is thrown during input then ios::badbit is turned on in *this's error state. (Exceptions thrown from basic_ios<>::clear() are not caught or rethrown.) If (exceptions()&badbit) != 0 then the exception is rethrown.

The content within the parenthesis is added by LWG defect 61, and does fix the ambiguity. However, it only fixed the 1 of 4 requirements, and it lost some context (the word "rethrown" is not seen before this sentence within this section).

[Lenexa 2015-05-07: Marshall to research and report]

[Kona 2022-11-08; this would be resolved by P1264]

[2022-11-22 Resolved by P1264R2 accepted in Kona. Status changed: Open → Resolved.]

Proposed resolution:

This wording is relative to N3797.

[Drafting note: The editor is kindly asked to introduce additional spaces at the following marked occurrences of operator&end drafting note]
  1. Modify 31.7.5.3.1 [istream.formatted.reqmts] p1 as indicated:

    -1- Each formatted input function begins execution by constructing an object of class sentry with the noskipws (second) argument false. If the sentry object returns true, when converted to a value of type bool, the function endeavors to obtain the requested input. If an exception, other than the ones thrown from clear(), if any, is thrown during input then ios::badbit is turned on[Footnote 314] in *this's error state. If (exceptions() & badbit) != 0 then the exception is rethrown. In any case, the formatted input function destroys the sentry object. If no exception has been thrown, it returns *this.

  2. Modify 31.7.6.3.1 [ostream.formatted.reqmts] p1 as indicated:

    -1- Each formatted output function begins execution by constructing an object of class sentry. If this object returns true when converted to a value of type bool, 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, other than the ones thrown from clear(), if any, is thrown during output, then ios::badbit is turned on[Footnote 327] in *this's error state. If (exceptions() & badbit) != 0 then the exception is rethrown. Whether or not an exception is thrown, the sentry object is destroyed before leaving the formatted output function. If no exception is thrown, the result of the formatted output function is *this.

  3. Modify 31.7.6.4 [ostream.unformatted] p1 as indicated:

    -1- Each unformatted output function begins execution by constructing an object of class sentry. If this object returns true, while converting to a value of type bool, the function endeavors to generate the requested output. If an exception, other than the ones thrown from clear(), if any, is thrown during output, then ios::badbit is turned on[Footnote 330] in *this's error state. If (exceptions() & badbit) != 0 then the exception is rethrown. In any case, the unformatted output function ends by destroying the sentry object, then, if no exception was thrown, returning the value specified for the unformatted output function.

  4. Modify 31.7.5.4 [istream.unformatted] p1 as indicated:

    -1- Each unformatted input function begins execution by constructing an object of class sentry with the default argument noskipws (second) argument true. If the sentry object returns true, when converted to a value of type bool, the function endeavors to obtain the requested input. Otherwise, if the sentry constructor exits by throwing an exception or if the sentry object returns false, when converted to a value of type bool, the function returns without attempting to obtain any input. In either case the number of extracted characters is set to 0; unformatted input functions taking a character array of non-zero size as an argument shall also store a null character (using charT()) in the first location of the array. If an exception, other than the ones thrown from clear(), if any, is thrown during input then ios::badbit is turned on[Footnote 317] in *this's error state. (Exceptions thrown from basic_ios<>::clear() are not caught or rethrown.) If (exceptions() & badbit) != 0 then the exception is rethrown. It also counts the number of characters extracted. If no exception has been thrown it ends by storing the count in a member object and returning the value specified. In any event the sentry object is destroyed before leaving the unformatted input function.