This is the mail archive of the mailing list for the libstdc++ project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

throwing on codecvt_base::error

On Sep 21, 2010, at 7:42 PM, Paolo Carlini wrote:

> About 9182-1, what I *do* remember is that we noticed with Petur (and
> Nathan) a number of circumstances where really we couldn't provide reach
> enough diagnostics to the user by way simply of return values from the
> concerned functions. In general I think this is recognized as a real
> issue in the current design of C++ iostreams. While I apply locally your
> patch and tweak the linker map, most likely reporting back that I'm
> going to commit your patch, you are welcome to start looking into the
> issue in more detail and suggest possible changes...

All good to hear!

Right, there's only one error code for failure. However, basic_filebuf also uses only one exception class, namely ios_base::failure. Having users test the what() string isn't a good solution. (An alternative is implementation-specific subclasses.)

The standard is very ambiguous about the exception specifications. overflow is the only function to mention exceptions in the Returns clause, but underflow and uflow are also mentioned in footnote 275 (attached to showmanyc). Furthermore, underflow has no defined return value for an invalid pending sequence, only for a "null" sequence. All such text is the basic_streambuf spec, not basic_filebuf, so it's not so specific. The text and footnote suggest that showmanyc should detect whether uflow and underflow will throw, which sounds to me like detecting e.g. whether a file is open or not. There is no way to pre-detect conversion failure, which makes this particular kind of throw more dangerous.

On the other hand, the user is allowed to throw from do_out and do_in. However, they might not want that to happen in all contexts. On the other however, there aren't many uses for codecvt outside basic_filebuf, being so esoteric and intrinsically limited.

There is another solution, which is to define certain values of state_type to represent errors. (For example, set the high-order bit of a scalar state_type.) Then, the user can retrieve it via a very simple change to _M_seek:

-	      __ret.state(_M_state_cur);
+      __ret.state(_M_state_cur);
     return __ret;

If sync incurs a codecvt error, seekoff(0,ios::cur) will as well. Does putting it in state() violate the requirement to return pos_type(off_type(-1))? Hmm, maybe it's OK. possibly says that state is significant when comparing fpos values, but the GNU implementation (bits/postypes.h) ignores it. It depends whether "equivalence relation" is interpreted per se, or in the context of other functions.

One thing we certainly can improve is, requirement 2: overflow is not allowed to consume characters that weren't output. Preserving the put area also preserves the cause of the error and the ability to recover from it. For example:

if ( ! my_stream.flush() ) { // flush also optionally throws an ios::failure
   // Something went wrong; attempt to correct error.
   // This requires a custom streambuf, and tapping into (redefined) _M_state_last.
   if ( my_stream.rdbuf()->my_check_put_area_for_error() ) {
       throw my_io_exception( "invalid input: ", my_stream.rdbuf()->my_get_put_area() );
   } else { // put area is OK, must be I/O error
       if ( ! my_stream.flush() ) { // retry
           throw my_io_exception( "unwritten data: ", my_stream.rdbuf()->my_get_put_area() );

Preserving the put area also allows for extending the optimized case of xsputn.

Well, that looks like enough discussion for one day. I've also coded up and tested the elimination of _M_reading and _M_writing, but that's less exciting.

	- Cheers,

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]