C++ 如果发生故障的析构函数可以';不要抛出异常
我注意到你不能在析构函数中抛出异常。所以我的问题是,如果析构函数失败,我应该怎么做 另一个问题是,在什么情况下,析构函数可能会失败C++ 如果发生故障的析构函数可以';不要抛出异常,c++,C++,我注意到你不能在析构函数中抛出异常。所以我的问题是,如果析构函数失败,我应该怎么做 另一个问题是,在什么情况下,析构函数可能会失败 非常感谢设计你的课程,让他们的导师不会因为设计而失败。如果d'tor中的某个内容可能引发异常,请在d'tor主体中捕获它并将其吞下(或者按照您喜欢的方式处理它,但不要重新抛出它)。忽略错误 例如,如果类包装某种输出,并且析构函数刷新并关闭该输出,则析构函数可能“失败”。写入数据可能会失败。然后,您可以选择终止程序,或者捕获异常,忽略错误,然后返回。通常正确的设计是忽
非常感谢设计你的课程,让他们的导师不会因为设计而失败。如果d'tor中的某个内容可能引发异常,请在d'tor主体中捕获它并将其吞下(或者按照您喜欢的方式处理它,但不要重新抛出它)。忽略错误 例如,如果类包装某种输出,并且析构函数刷新并关闭该输出,则析构函数可能“失败”。写入数据可能会失败。然后,您可以选择终止程序,或者捕获异常,忽略错误,然后返回。通常正确的设计是忽略它 在我的示例中,该类还应该有一个“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;
}
无论哪种方式,只有当其他东西抛出异常并且对象在堆栈展开期间被销毁时,用户才会在不显式刷新的情况下销毁对象。因此,他们已经知道自己的操作失败了,如果有必要,他们可以回滚事务或其他任何必须执行的操作以响应失败。应该编写析构函数,使其不会失败。释放资源应该是您在析构函数本身中所做的唯一事情。对于进一步的“去初始化”过程,使用不同的方法。我不同意析构函数应该“设计成不会失败”——当然它们也会失败。例如,在析构函数中调用fclose()可能会失败。现在的问题是怎么做?在我看来,有两种选择:
- 别理它。这具有简单的优点,但您永远不会知道失败发生了,这可能意味着隐藏bug
- 记录下来。这样做的问题是,无法保证写入日志也不会失败,或引发其他问题
这并不局限于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失败的情况下,您可以手动调用dispose
方法并处理潜在的故障
dispose方法的确切代码取决于您想要的结果(例如,dispose是否应该是多线程安全的,dispose失败的对象是否应该被视为“已经disposed”,等等)
难道没有其他方法来表示错误吗?
当然有,但无论如何,它们都是以全球资源为基础的
例如,您可以在控制台或文本文件中记录故障
另一个方法是设置一些全局变量,但这通常是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...
}
}
但这种代码应该是例外。我记得是我想象出来的,但不记得是否使用过它(虽然我使用了一个变体作为计时器…)+1:这可能是一个堆芯泄漏,你对此无能为力。尼尔-我的回答提到使用单独的方法进行更高级的清理……fclose()将属于这一类。这样,方法可以选择如何处理异常,而不是d'tor本身。事情当然会失败,我只是更喜欢清理方法,而不是把所有的代码都放在d'tor中。即使失败,流也将与文件解除关联,因此除了日志记录之外,其他任何有用的操作都无法完成?这会不会使“反初始化”更容易被跳过?我同意UncleBens的观点。这打败了雷伊。使用异常安全代码是一种方法,对于析构函数(除其他外),代码必须为nothrow/nofail。这是100%错误的。如何确保析构函数100%安全?