如果失败的析构函数不能抛出异常该怎么办

时间:2010-03-16 18:14:47

标签: c++

我注意到你不能在析构函数中抛出异常。所以我的问题是如果析构函数失败我应该怎么做。

另一个问题是,在什么情况下析构函数可能会失败?

非常感谢

5 个答案:

答案 0 :(得分:14)

忽略错误。

如果类包装某种输出,析构函数可能会“失败”,析构函数会刷新并关闭该输出。写入数据可能会失败。您的选择是终止程序,或捕获异常,忽略错误,然后返回。通常,正确的设计是忽略它。

在我的示例中,该类还应该具有“close_and_flush”函数,如果用户想要知道它是否成功,则可以在对象销毁之前调用该函数。如果您的班级用户不关心操作是否失败,那么您也不会,并且您可以安全地抑制该异常。

用户可以编写如下代码:

{
    OutputObject OO;
    write some stuff to OO, might throw;
    do more things, might throw;
    try {
        OO.flush_and_close();
    } catch (OutputException &e) {
        log what went wrong;
        maybe rethrow;
    }
}

或者这个:

try {
    OutputObject OO;
    write some stuff to OO, might throw;
    do more things, might throw;
    OO.flush_and_close();
} catch (AnyOldException &e) {
    log what went wrong;
    maybe rethrow;
}

无论哪种方式,在没有用户显式刷新的情况下,对象将被销毁的唯一时间是,如果其他东西抛出异常并且在堆栈展开期间对象被销毁。所以他们已经知道他们的操作失败了,如果有必要,他们可以回滚交易或他们为了应对失败而必须做的其他事情。

答案 1 :(得分:8)

设计你的课程,他们的设计不会失败。如果d'tor中的某些东西可以抛出一个例外,那就把它抓住,然后吞下它(或者按照它的方式处理它,但不要重新抛出它)。

答案 2 :(得分:6)

我不同意这样的想法,即析构函数应该“设计为不会失败” - 当然它们可能会失败。例如,在析构函数中调用fclose()可能会失败。现在问题是该怎么办呢?我认为,有两种选择:

  • 忽略它。这具有简单的优点,但你永远不会知道失败发生,这可能意味着隐藏错误。

  • 记录下来。这样做的问题是,无法保证写入日志也不会失败,或触发其他一些问题。

如果这让你没有明智的话,那对我来说也是一样的!基本上,没有完美的解决方案。您需要根据具体情况从上述两个选项中进行选择。决定的一种方法是思考“如果这是C代码(没有析构函数),我该怎么办?” - 如果您忽略C中的问题,也可以在C ++中忽略它,

答案 3 :(得分:3)

应该编写析构函数,使其不会失败。释放资源应该是你在析构函数本身中所做的唯一事情。使用单独的方法进一步“去初始化”程序。

答案 4 :(得分:2)

析构函数不能抛出!

RAII建立在这个基础之上,因此从析构函数中抛出会打开RAII打破你的可能性。

这不仅限于C ++。无论语言或框架如何,您通常都不希望处理失败以破坏程序的执行。

但我想扔!!!!

如果你认为你的对象应该抛弃资源,那么你应该手工制作:

class MyObject
{
    public :
       // etc.
       ~MyObject()
       {
          try
          {
             this->dispose() ;
          }
          catch(...) { /* log the problem, or whatever, but DON'T THROW */ }
       }

       void dispose()
       {
          if(this->isAlreadyDisposed == false)
          {
             this->isAlreadyDisposed = true ;

             // dispose the acquired resource          
          }
       }
} ;

这样,默认情况下,您的对象可以正常使用RAII。但是在您应该知道处置失败的情况下,您可以手动调用dispose方法并处理潜在的失败。

配置方法的确切代码取决于您想要的结果(例如,应该配置多线程是否安全,如果配置失败的对象被视为“已经处置”或未经处理等)。

是否有另一种方式来发出错误信号?

当然有,但无论如何它们都是以全球资源为基础的。

例如,您可以在控制台或文本文件中记录故障。

另一个是设置一些全局变量,但这通常是你可以用于C ++的最脏的技巧。另一种方法是调用某种处理程序,但同样,你不能在通用处理程序中做很多事情,因为它不知道如何处理你的错误。

在一个案例中,我写了一个构造函数,它在构造时引用了一个布尔值。类似的东西:

class MyObject
{
    bool & isOk ;

    public :
       // etc.
       MyObject(bool & p_isOk) : isOk(p_isOk) {}

       ~MyObject()
       {
          // dispose of the ressource
          // If failure, set isOk to false ;
       }
} ;

可以用作:

void foo()
{
   bool isOk = true ;

   // etc.

   {
      MyObject o(isOk) ;
      // etc.
   }


   if(isOk == false)
   {
      // Oops...
   }
}

但是这种代码应该是例外的。我记得我想象过它,但是不记得它是否被使用了(虽然我使用了计时器的变体......)。