C++项目具有精心设计的异常机制

Uni*_*ant 7 c++ exception

有没有人知道一个开源c ++应用程序与一个设计良好/强大的异常机制,所以我可以获得一些灵感?我看到的大多数代码/示例都有可疑的事情:

  1. 使用消息字符串作为参数抛出对象.似乎错了,因为它将异常标记为致命,可以向用户显示的错误消息更高,为客户端代码尝试处理异常留下了很小的空间.即使异常是致命的,像diffirent locales(语言)之类的东西也会让我在抛出点时格式化一条消息对我来说是一个坏主意.
  2. 使用从基本异常类派生的大量不同的异常类.为每一个可能出错的东西(打开文件,读取文件,写入文件,创建线程等)引入新的类/类型,感觉不对.使用基类型捕获最高级别的所有未处理异常会丢失显示有意义错误消息所需的类型信息.
  3. 对每个组件/库使用从基本异常类派生的一个异常类,并为其指定错误代码作为参数以指示确切的错误.使用基本类型捕获会导致模糊不清.(我们捕获了谁的错误代码"3"?)...

一些正确方向的指针将受到欢迎.

Chr*_* A. 5

为了解决所有这三个问题,我发现对我来说最好的方法是抛出自定义的异常,该异常源自std::runtime_error。像这样:

#include <exception>

class ChrisAException : public std::runtime_error
{
      /// constructor only which passes message to base class
      ChrisAException(std::string msg)
      : std::runtime_error(msg)
      {

      }
}
Run Code Online (Sandbox Code Playgroud)

它允许接受一个字符串,我总是将其以类似以下格式的形式x输入(假定negative为无效输入,意味着调用它的内容有误):

#include "ChrisAException.h"

void myfunction(int x)
{

    if(x < 0) 
    {
        throw ChrisAException("myfunction(): input was negative!");
    }

    // rest of your function
} 
Run Code Online (Sandbox Code Playgroud)

对于这一点,请记住,对于程序员而言,这些异常中的字符串比最终用户更多。发生故障时,界面工作的程序员是在语言环境中显示有意义的内容。可以在调试时记录或查看异常中的字符串(最好!)。

这样,您最终可以通过以下方式抓住它:

try
{
      // high level code ultimately calling myfunction

}
catch(ChrisAException &cae)
{
       // then log cae.what()
}
catch(std::runtime_error &e)
{
       // this will also catch ChrisAException's if the above block wasn't there
}
catch(...)
{
      // caught something unknown
}
Run Code Online (Sandbox Code Playgroud)

我个人不喜欢派生太多类型的异常或给出错误代码。我让字符串消息进行报告。

通常,我使用C ++异常来表示“程序出了点问题”,而不是处理正常的用例。因此,对我来说,在算法执行过程中引发的异常要么意味着“向用户发出错误提示标志”,要么“不告诉用户”(取决于代码对他们正在执行的操作的严格程度),但肯定会记录下来让程序员知道。

我不使用C ++异常来处理本质上不是编程错误的情况,例如某种不正确的逻辑或被称为错误的情况。例如,我不会使用C ++异常来处理正常的程序情况,例如DVD刻录程序的驱动器中没有空DVD。为此,我将有明确的返回码,使用户可以知道是否有空DVD(可能带有对话框等)。

请记住,C ++异常处理的一部分是将堆栈展开为一个try-catch块。对我而言,这意味着中止程序中正在发生的事情并清理堆栈。在类似我的DVD示例的情况下,您不应该真正想放松很多堆栈。这不是灾难性的。您应该只让用户知道,然后让他们再试一次。

再次重申,这是我根据经验和阅读情况使用C ++异常的首选方式。我愿意接受其他意见。

编辑:更改std::exceptionstd::runtime_error基于评论者的建议。

  • `std :: exception`没有只有字符串的构造函数,只有在MSVC的(非一致性)实现中。不是很重要,但仍然很重要。对于遵循这方面标准的编译器,您可以改用`std :: runtime_error`。 (3认同)
  • @MooingDuck:如果输入了catch(...)块,程序如何保持未知状态?平仓发生了,析构函数运行了,事务回滚了,内存被释放了。发生了问题,但您的不变量受到了保护。 (2认同)