Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I give streams better exception messages?

The problem

As of right now, the exception support for streams are terrible. When the Boost.System library was adopted into C++11, one was given the impression that maybe exceptions would improve. All the change did was replace std::exception with std::system_error. While <system_error> is a good library on its own for developers, the standard committee and standard library implementors have not taken any steps towards using it to improve exception messages.

To give an idea of how terrible it is, here's a brief summary of what goes down:

  • An error occurs.

  • setstate is used to set badbit or failbit.

  • clear is called by setstate.

  • If exceptions are enabled, clear will throw an ios_base::failure.

Yes, that means for ALL errors the same useless exception message is thrown. This is specified at the basic_ios level, so all derived classes suffer from this issue. The offending quote:

[iostate.flags]/4 Effects: If ((state | (rdbuf() ? goodbit : badbit)) & exceptions()) == 0, returns. Otherwise, the function throws an object fail of class basic_ios::failure (27.5.3.1.1), constructed with implementation-defined argument values.

Here's an example of what "implementation-defined argument values" gives us:

ios_base::clear: unspecified iostream_category error

Is there an easy fix?

Neither Boost.Filesystem nor Boost.Iostreams are replacements for <iostream>. The former is a library for portably dealing with a filesystem (and is likely to appear in the next revision of C++) while the latter has something to do with..Sources and Sinks. The documentation states that it delegates exceptions to ios_base::failure anyways. Boost.Filesystem does provide <boost/filesystem/fstream.hpp> which uses path instead of const char* arguments to open(). It shows an example of how one might inherit from standard library classes:

  template < class charT, class traits = std::char_traits<charT> >
  class basic_ifstream : public std::basic_ifstream<charT,traits>
  {
  private: // disallow copying
    basic_ifstream(const basic_ifstream&);
    const basic_ifstream& operator=(const basic_ifstream&);

  public:
    basic_ifstream() {}

    // use two signatures, rather than one signature with default second
    // argument, to workaround VC++ 7.1 bug (ID VSWhidbey 38416)

    explicit basic_ifstream(const path& p)
      : std::basic_ifstream<charT,traits>(p.BOOST_FILESYSTEM_C_STR, std::ios_base::in) {}

    basic_ifstream(const path& p, std::ios_base::openmode mode)
      : std::basic_ifstream<charT,traits>(p.BOOST_FILESYSTEM_C_STR, mode) {}

    void open(const path& p)
      { std::basic_ifstream<charT,traits>::open(p.BOOST_FILESYSTEM_C_STR, std::ios_base::in); }

    void open(const path& p, std::ios_base::openmode mode)
      { std::basic_ifstream<charT,traits>::open(p.BOOST_FILESYSTEM_C_STR, mode); }

    virtual ~basic_ifstream() {}
  };

This is a neat trick, except since our offending function is non-virtual and all the way up in basic_ios, there's a combinatorial explosion of what we have to reimplement:

iostream inheritance diagram

I suspect an entire rewrite is needed because simply replacing clear() won't be enough. The stream can fail for multiple reasons but there's only one type of exception thrown. While std::system_error gives us better tools of expressing errors, that doesn't help if, again, there's no way to distinguish the source of the error.

However I'm not a library writer and don't feel like taking on this task. Are there any other options than the ones I listed?

like image 837
user5378483 Avatar asked Sep 26 '15 06:09

user5378483


1 Answers

Boost is an open source project so the way I see it there are 2 options:

  1. Complain. Either write a bug report or get on the mailing list and suggest an enhancement or both. If the community thinks you have a good point, someone might take it on
  2. Do 1, then do something about it. You'll probably get some support from the community. You might no be a library writer, but maybe the people behind boost were not either, until they were.

There is no magic way to fix it, someone has to do the work.

like image 129
ventsyv Avatar answered Nov 07 '22 21:11

ventsyv