2014-03-06 38 views
0

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

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类的每个公共方法的语句。另外,我想避免宏,我更喜欢C++ 11解决方案。我正在考虑引入一个ExceptionGuard类,该类将作为其构造函数的参数solve_impl方法,并将在那里执行try/catch。我试图用std :: function来传递方法,但我有点失败。你必须建议一个更优雅的解决方案吗?谢谢。

+3

您应该[1]在基类中声明虚函数为'noexcept',以防止派生类抛出异常,或者[2]定义一组异常可能会被抛出然后捕获那些(并使用[异常翻译器]处理它们(http://blogs.msdn.com/b/vcblog/archive/2014/01/16/exception-boundaries.aspx)。 catch'...';你不知道什么可能出错或者系统的状态 –

+0

我不太确定noexcept是什么,但是如果我把虚函数声明为noexcept,什么都不会改变。 – AstrOne

+1

声明虚函数hook noexcept并不能真正解决OP的问题如果没有'try' /'catch'块,应用程序崩溃是因为插件抛出一个未处理的异常。 'noexcept',应用程序崩溃,因为插件违反了异常规范,运行时调用'terminate()'。 –

回答

1

What if the user provides his own plugin but his code throws an unhanded exception? This will make the application to crash and the server will go offline.

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

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

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

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