检测析构函数中的活动异常

时间:2011-04-01 09:34:29

标签: c++ exception destructor raii

我有一个使用RAII进行清理的类,以防出现问题。这意味着该类包含一个标志,告诉它是否已完成工作,并且如果在调用构造函数时未设置此标志,则它正在执行清理任务并生成日志消息。现在我希望这个类变得更聪明一步,即它应该找出,如果错误发生了,因为工作被贬低(即抛出异常并且析构函数被调用)或者因为有人错过了这个类而且从不实际上完成了工作。这意味着如果异常处于活动状态,我必须在析构函数中找到它。如果找到一个,我会生成一条日志消息,可能会打印异常的内容然后重新抛出它。我猜是这样的。

Foo::~Foo () {
  try { /* do not know what to put here */ }
  catch( const std::exception & ex ) {
     // produce error in log
     throw;
  }
  catch( ... ) {
    // produce some other log message
    throw;
   }
}

但是我不确定这是否会起作用,因为异常在调用析构函数之前已经激活,并且不是来自try块。此外,我在析构函数中使用throw;并在此时抛出异常是一个非常糟糕的主意。所以我不会这样做,除非标准明确保证这个案例是这个规则的例外(没有双关语)(我不知道)。

这是可能的,或者我应该以其他方式处理这种情况?

3 个答案:

答案 0 :(得分:11)

您可以使用std::uncaught_exception(),如果抛出异常但catch尚未处理,则返回true。您可以在析构函数中使用此检查来决定它应该或不应该做什么。

需要注意的是,良好的编程指南通常要求在不同情况下让析构函数表现出不同的表现通常不是一个好主意。所以使用此功能,但不要滥用它。一个常见的用法是让析构函数只在没有活动的未捕获异常时抛出(此函数返回false)。但这种行为通常不是好的设计。如果条件足够严重以保证例外,则可能不应忽略它。并且析构函数不应该抛出异常。

示例:

Foo::~Foo()
{
    if (std::uncaught_exception()) 
    {
        std::cerr << "Warning: Can't cleanup properly" << std::endl;
        return;
    }
    else
    {
        // ...
    }
}

答案 1 :(得分:2)

不可能以安全的方式进行。

你可以做的是检查析构函数中的参数,这应该判断处理是否已经完成。

顺便说一下,为什么不在catch块中记录错误,你可以在哪里实际处理错误?在那里你应该知道处理因错误而终止。

答案 2 :(得分:1)

看看这个question of mine and the responses

基本上,您可以在第一个try块中使用简单的throw重新抛出当前活动的异常。但是,如果您确定当前正在处理异常,那么只是安全的,即从catch块中调用析构函数。否则,throw将调用std::terminate()

Foo::~Foo () {
  try {  throw; } // only if you *know* that an exception is active - bad thing for a generic destructor
  catch( const std::exception & ex ) {
     // produce error in log

  }
  catch( ... ) {
    // produce some other log message

   }
}

但是,在析构函数中抛出异常是不受欢迎的,因此我不会在之后重新抛出异常。总而言之,整件事对我来说并不是一个好主意。

异常处理模式很好,但我不会在不相关的析构函数中执行此操作。再次,请参阅引用的问题。