如何为流提供更好的异常消息?

use*_*483 39 c++ c++-standard-library c++11

问题

截至目前,对流的异常支持非常糟糕.当Boost.System库被采用到C++ 11中时,给人的印象是可能会有异常改进.所有的变化所做的替换std::exceptionstd::system_error.虽然<system_error>开发人员本身就是一个很好的库,但标准委员会和标准库实现者并未采取任何措施来使用它来改进异常消息.

为了说明它有多糟糕,这里简要总结了下面的内容:

  • 发生错误.

  • setstate用于设置badbitfailbit.

  • clear被称为setstate.

  • 如果启用了异常,clear则会抛出异常ios_base::failure.

是的,这意味着对于所有错误,抛出相同的无用异常消息.这是在basic_ios级别指定的,因此所有派生类都会遇到此问题.违规报价:

[iostate.flags]/4 效果:如果((state | (rdbuf() ? goodbit : badbit)) & exceptions()) == 0,返回.否则,该函数抛出一个failbasic_ios::failure(27.5.3.1.1)的对象,使用实现定义的参数值构造.

以下是"实现定义的参数值"为我们提供的示例:

ios_base::clear: unspecified iostream_category error
Run Code Online (Sandbox Code Playgroud)

有一个简单的解决方案吗?

既不是Boost.Filesystem也不Boost.Iostreams是替代品<iostream>.前者是一个可以轻松处理文件系统的库(很可能出现在C++的下一个版本中),而后者与.sources和Sinks有关.该文档声明它ios_base::failure无论如何都要委托例外.Boost.Filesystem 确实提供<boost/filesystem/fstream.hpp>了使用path而不是const char*参数open().它显示了一个如何从标准库类继承的示例:

  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() {}
  };
Run Code Online (Sandbox Code Playgroud)

这是一个巧妙的技巧,除非我们的违规功能是非虚拟的并且一直在进行basic_ios,因此我们必须重新实现的组合爆炸:

iostream继承图

我怀疑需要整个重写,因为简单的替换clear()是不够的.流可能由于多种原因而失败,但只抛出一种类型的异常.虽然std::system_error为我们提供了更好的表达错误的工具,但如果再次无法区分错误的来源,则无济于事.

但是,我不是图书馆作家,也不想承担这项任务.除了我列出的选项之外还有其他选择吗?

ven*_*syv 3

Boost 是一个开源项目,所以我认为有 2 个选项:

  1. 抱怨。要么写一个错误报告,要么进入邮件列表并提出改进建议,或者两者兼而有之。如果社区认为你的观点很好,有人可能会接受它
  2. 做1,然后做一些事情。您可能会从社区获得一些支持。你可能不是图书馆作家,但也许 boost 背后的人也不是,直到他们成为。

没有什么神奇的方法可以解决这个问题,必须有人来做这项工作。