我注意到你不能在析构函数中抛出异常。所以我的问题是如果析构函数失败我应该怎么做。
另一个问题是,在什么情况下析构函数可能会失败?
非常感谢
答案 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)
这不仅限于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...
}
}
但是这种代码应该是例外的。我记得我想象过它,但是不记得它是否被使用了(虽然我使用了计时器的变体......)。