c++ - How do I give streams better exception messages? -


the problem

as of right now, exception support streams terrible. when boost.system library adopted c++11, 1 given impression maybe exceptions improve. change did replace std::exception std::system_error. while <system_error> library on own developers, standard committee , standard library implementors have not taken steps towards using improve exception messages.

to give idea of how terrible is, here's brief summary of goes down:

  • an error occurs.

  • setstate used set badbit or failbit.

  • clear called setstate.

  • if exceptions enabled, clear throw ios_base::failure.

yes, means errors same useless exception message thrown. specified @ basic_ios level, derived classes suffer issue. offending quote:

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

here's example of "implementation-defined argument values" gives us:

ios_base::clear: unspecified iostream_category error 

is there easy fix?

neither boost.filesystem nor boost.iostreams replacements <iostream>. former library portably dealing filesystem (and appear in next revision of c++) while latter has with..sources , sinks. documentation states delegates exceptions ios_base::failure anyways. boost.filesystem does provide <boost/filesystem/fstream.hpp> uses path instead of const char* arguments open(). shows example of how 1 might inherit 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 2 signatures, rather 1 signature default second     // argument, 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 neat trick, except since our offending function non-virtual , way in basic_ios, there's combinatorial explosion of have reimplement:

iostream inheritance diagram

i suspect entire rewrite needed because replacing clear() won't enough. stream can fail multiple reasons there's one type of exception thrown. while std::system_error gives better tools of expressing errors, doesn't if, again, there's no way distinguish source of error.

however i'm not library writer , don't feel taking on task. there other options ones listed?

boost open source project way see there 2 options:

  1. complain. either write bug report or on mailing list , suggest enhancement or both. if community thinks have point, might take on
  2. do 1, it. you'll support community. might no library writer, maybe people behind boost not either, until were.

there no magic way fix it, has work.


Comments