在C ++中处理来自基类的重写方法的异常

时间:2014-03-06 06:04:55

标签: c++ c++11 exception-handling

我正在编写一个程序(实际上是一个库),它应该对给定的数据集进行某种处理。该程序有一个插件机制。每个插件都遵循不同的数据处理策略。这个想法是用户可以在插件中创建自己的处理策略,他不必触摸程序的代码。该软件是基于服务器的应用程序,它永远不会终止。问题如下:如果用户提供自己的插件但他的代码抛出未处理的异常怎么办?这将使应用程序崩溃,服务器将脱机。鉴于插件总是创建一个对象,该对象派生自库和插件可见的类,显而易见的解决方案是:

class AbstractSolver
{
public:
    void solve(void)
    {
        try {
        this->solve_impl();
        } catch (...) {
            std::cout << "got exception" << std::endl;
        }
    }
private:
    virtual void solve_impl(void) = 0;
};

// This is the class of the plugin
class MySolver : public AbstractSolver
{
private:
    void solve_impl(void)
    {
        throw std::exception();
    }
}

虽然这可行,但我不想为AbstractSolver类的每个公共方法编写try和catch语句。另外,我想避免使用宏,我更喜欢使用c ++ 11解决方案。我正在考虑引入一个ExceptionGuard类,它将其构造函数的参数作为solve_impl方法,并在那里执行try / catch。我尝试使用std :: function来传递方法,但我有点失败。你必须建议一个更优雅的解决方案吗?谢谢。

1 个答案:

答案 0 :(得分:1)

  

如果用户提供自己的插件但他的代码会抛出一个无法处理的异常怎么办?这将使应用程序崩溃,服务器将脱机。

如果用户提供的插件抛出了插件规范不允许的异常,那么这是用户提供的插件中的逻辑错误。检测到逻辑错误时要做的正确做法是立即停止执行并终止进程(可能是在最后一次尝试记录失败或通知系统中其他组件即将终止之后)。

你不妨问一下“如果用户提供自己的插件但他的代码通过空指针执行间接怎么办?”或“如果用户提供他自己的插件但他的代码进入无限循环或导致死锁并且永远不会返回怎么办?”逻辑错误是一个逻辑错误:当您检测到它时,您无法知道进程的状态以及继续执行是否安全。

如果插件不能抛出异常,则在基类中将虚函数声明为noexcept。这将要求派生类中的所有覆盖也是noexcept。如果覆盖无法处理异常并且异常在noexcept边界内泄漏,则将调用std::terminate(),从而终止执行。如果您需要能够在终止时重新启动服务,请考虑使用监视服务的监视程序进程。

对于在异常边界处理异常的更一般问题,请考虑使用异常转换器并包装可能抛出lambda表达式的代码。我写了一篇详细的文章:"Exception Boundaries."