Formatted input function and exceptions

42 views
Skip to first unread message

Jean-Marc Bourguet

unread,
Aug 20, 2016, 8:16:42 AM8/20/16
to ISO C++ Standard - Discussion
The requirements on formatted input functions state:

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 is thrown during input then ios::badbit is turned on[312] 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.

With the note 312 stating "This is done without causing an ios::failure to be thrown."

This is from N4604 but if I'm not mistaken the requirements didn't change since C++98 in a way which is significant for my questions.

1/ How can a program observe that an ios::failure is thrown and shallowed when ios::badbit is turned on?

2/ Can a program implement new formatted input functions respecting that requirement for its own types? basic_ios seems to lack an adequate interface.

Yours,

--
Jean-Marc

Edward Catmur

unread,
Aug 21, 2016, 8:24:03 AM8/21/16
to ISO C++ Standard - Discussion
On Saturday, 20 August 2016 13:16:42 UTC+1, Jean-Marc Bourguet wrote:
The requirements on formatted input functions state:

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 is thrown during input then ios::badbit is turned on[312] 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.

With the note 312 stating "This is done without causing an ios::failure to be thrown."

This is from N4604 but if I'm not mistaken the requirements didn't change since C++98 in a way which is significant for my questions.

1/ How can a program observe that an ios::failure is thrown and shallowed when ios::badbit is turned on?

I assume you meant to type "swallowed". I'm still not sure what you mean - ios::failure is not thrown, so it cannot be observed to be thrown let alone swallowed.

2/ Can a program implement new formatted input functions respecting that requirement for its own types? basic_ios seems to lack an adequate interface.
 
This is rather unclear, but my interpretation of "if an exception is thrown during input" is that this refers to exceptions thrown by the underlying streambuf machinery (e.g. a file permission error or a closed stream), and not to exceptions raised converting extracted data (e.g. an encoding error, an invalid character in an integer conversion, or a failure to allocate memory for the object being extracted into).

As such, there is no need for the program to worry about respecting this requirement; it can just call the formatted and unformatted input functions and they will take care of it. It is only if you intend to access rdbuf() directly that the requirement comes into play. It is true that there is no interface to set badbit without throwing ios::failure, but you can always clear badbit in the exceptions mask, set badbit in the error state, then restore the exceptions mask. If you're writing lots of formatted input functions that access rdbuf() directly, you might want to write utility functions for this, but the intent is that the provided formatted and unformatted functions should be sufficient in most cases e.g. you can extract into a char array or string and then perform further parsing or object construction.

A note of warning: Many existing implementations have various defects in their own handling of this corner of the interface (when the exceptions mask is nonzero), so when testing your program don't assume that the underlying implementation is behaving correctly.

Jean-Marc Bourguet

unread,
Aug 21, 2016, 10:51:31 AM8/21/16
to ISO C++ Standard - Discussion
Le dimanche 21 août 2016 14:24:03 UTC+2, Edward Catmur a écrit :
On Saturday, 20 August 2016 13:16:42 UTC+1, Jean-Marc Bourguet wrote:
The requirements on formatted input functions state:

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 is thrown during input then ios::badbit is turned on[312] 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.

With the note 312 stating "This is done without causing an ios::failure to be thrown."

This is from N4604 but if I'm not mistaken the requirements didn't change since C++98 in a way which is significant for my questions.

1/ How can a program observe that an ios::failure is thrown and shallowed when ios::badbit is turned on?

I assume you meant to type "swallowed".

Right.
 
I'm still not sure what you mean - ios::failure is not thrown, so it cannot be observed to be thrown let alone swallowed.

By swallowing I meant the technique I was familiar with (see Langer&Kreft for instance), something like:

std::istream& operator>>(std::istream& is, std::string& s) {
   try {
      std::istream::sentry guard(is);
      // do the input
   } catch (...) {
      if (exceptions() & std::ios_base::badbit) {
         try { is.setstate(ios_base::badbit); } catch (...) {}
         throw;
      } else {
         is.setstate(ios_base::badbit);
      }
   }
   return is;
}

the above language seems to mandate to replace the catch by

   catch(...) {
      is.__set_state_and_rethrow_if_needed_without_throwing_failure(ios_base::badbit);
   }

(and a look at GNU and LLVM library sources show that's what they are using, with a reference to that paragraph for GNU) I was wondering how it was possible for a program to see the difference. If it isn't possible, why is there such mandate?

2/ Can a program implement new formatted input functions respecting that requirement for its own types? basic_ios seems to lack an adequate interface.
 
This is rather unclear, but my interpretation of "if an exception is thrown during input" is that this refers to exceptions thrown by the underlying streambuf machinery (e.g. a file permission error or a closed stream), and not to exceptions raised converting extracted data (e.g. an encoding error, an invalid character in an integer conversion, or a failure to allocate memory for the object being extracted into).

As such, there is no need for the program to worry about respecting this requirement; it can just call the formatted and unformatted input functions and they will take care of it. It is only if you intend to access rdbuf() directly that the requirement comes into play. It is true that there is no interface to set badbit without throwing ios::failure, but you can always clear badbit in the exceptions mask, set badbit in the error state, then restore the exceptions mask.

If I'm not mistaken, restoring the exception mask will throw a ios::failure.
 
If you're writing lots of formatted input functions that access rdbuf() directly, you might want to write utility functions for this, but the intent is that the provided formatted and unformatted functions should be sufficient in most cases e.g. you can extract into a char array or string and then perform further parsing or object construction.

I find it easier to get the boundary conditions right by accessing the streambuf and then setting the state of the stream than by using the formatted or unformatted functions.  It may be well that's something having more to do with familiarity than something fundamental, but at least respecting the width setting seems far more easy without using formatted functions.  In fact, even if it is possibly to observe a difference between my usual technique and what the standard mandates for formatted functions, I may consider that continuing to use it is the right trade-off (the difference is probably arcane if I've not seen it yet, an exceptions mask nonzero is already not that common).

Yours,

--
Jean-Marc

Edward Catmur

unread,
Aug 21, 2016, 12:14:58 PM8/21/16
to std-dis...@isocpp.org
On Sun, Aug 21, 2016 at 3:51 PM, Jean-Marc Bourguet <jm.bo...@gmail.com> wrote:
By swallowing I meant the technique I was familiar with (see Langer&Kreft for instance), something like:

std::istream& operator>>(std::istream& is, std::string& s) {
   try {
      std::istream::sentry guard(is);
      // do the input
   } catch (...) {
      if (exceptions() & std::ios_base::badbit) {
         try { is.setstate(ios_base::badbit); } catch (...) {}
         throw;
      } else {
         is.setstate(ios_base::badbit);
      }
   }
   return is;
}

the above language seems to mandate to replace the catch by

   catch(...) {
      is.__set_state_and_rethrow_if_needed_without_throwing_failure(ios_base::badbit);
   }

(and a look at GNU and LLVM library sources show that's what they are using, with a reference to that paragraph for GNU) I was wondering how it was possible for a program to see the difference. If it isn't possible, why is there such mandate?

There isn't any observable difference, so there isn't any difference by [intro.execution]. It's simpler and more understandable (at least, for those users who aren't writing their own low-level input/output functions) for the Standard to say "without causing an ios::failure to be thrown" than to say "if an ios::failure is thrown, it is caught and discarded". 

2/ Can a program implement new formatted input functions respecting that requirement for its own types? basic_ios seems to lack an adequate interface.
 
This is rather unclear, but my interpretation of "if an exception is thrown during input" is that this refers to exceptions thrown by the underlying streambuf machinery (e.g. a file permission error or a closed stream), and not to exceptions raised converting extracted data (e.g. an encoding error, an invalid character in an integer conversion, or a failure to allocate memory for the object being extracted into).

As such, there is no need for the program to worry about respecting this requirement; it can just call the formatted and unformatted input functions and they will take care of it. It is only if you intend to access rdbuf() directly that the requirement comes into play. It is true that there is no interface to set badbit without throwing ios::failure, but you can always clear badbit in the exceptions mask, set badbit in the error state, then restore the exceptions mask.

If I'm not mistaken, restoring the exception mask will throw a ios::failure.

Oh, yeah. So you'll have to use the technique you describe above.
 
If you're writing lots of formatted input functions that access rdbuf() directly, you might want to write utility functions for this, but the intent is that the provided formatted and unformatted functions should be sufficient in most cases e.g. you can extract into a char array or string and then perform further parsing or object construction.

I find it easier to get the boundary conditions right by accessing the streambuf and then setting the state of the stream than by using the formatted or unformatted functions.  It may be well that's something having more to do with familiarity than something fundamental, but at least respecting the width setting seems far more easy without using formatted functions.  In fact, even if it is possibly to observe a difference between my usual technique and what the standard mandates for formatted functions, I may consider that continuing to use it is the right trade-off (the difference is probably arcane if I've not seen it yet, an exceptions mask nonzero is already not that common).

I can't see any way it could be possible to see a difference. All the code in question is supplied either by yourself or by the implementation, and the implementation is constrained to act within the Standard.

Jean-Marc Bourguet

unread,
Aug 21, 2016, 12:19:58 PM8/21/16
to ISO C++ Standard - Discussion
Thanks to have confirmed what I thought. I was fearing that I missed something which could have been more important in another context that this one.
Reply all
Reply to author
Forward
0 new messages