在 C++ 中,如何检测析构函数是由于异常抛出导致栈被卷回而运行,而不是由于作用域正常退出触发析构函数?我想知道这一点,以便创建一个类,该类具有某些清理代码,总是在正常退出时运行,但在异常发生时跳过。
在 C++ 中,如何检测析构函数是由于异常抛出导致栈被卷回而运行,而不是由于作用域正常退出触发析构函数?我想知道这一点,以便创建一个类,该类具有某些清理代码,总是在正常退出时运行,但在异常发生时跳过。
std::uncaught_exception()
(定义在<exception>
中)可以告诉您在析构函数中是否由于异常而调用:
class A
{
public:
~A()
{
if (std::uncaught_exception()) {
// Called because of an exception
} else {
// No exception
}
}
};
也许这篇文章能帮到您。该文章将展示std::uncaught_exception()的问题,并提供了如何在析构函数中处理异常的建议。
uncaught_exceptions
不是稳健的。 - Mark Lakata除非你有充分的理由,否则不要这样做。堆栈展开是一种语言特性,所有在try
块内的自动对象都将被强制释放,以便其中的资源有机会释放。
你想在堆栈展开期间跳过dtor中的清理,这将绕过它的原始意图。而且你将冒着泄漏资源的风险。
示例
class CDBConnection
{
public:
CDBConnection()
{
m_db.open();
}
~CDBConnection()
{
if (!std::uncaught_exception())
m_db.close();
// if this is called during a stack unwinding,
// your DB connection will not be closed for sure.
// That's a resource leakage.
}
//..
private:
DB m_db;
};
void main()
{
//..
try
{
// code that may throw
CDBConnection db;
//..
}
catch(const CDBException& exp)
{
// properly handle the exception
}
}
这是我能想到的一种方法,但它似乎有些笨拙:
{
myCleanupClass unwindAction;
try {
// do some work which may throw exception.
} catch (...) {
unwindAction.disableDestructorWork();
throw;
}
}
stack
日志记录。类似于Log xxx("funcA - ", arg1, arg2, arg3);
,但是仪器化函数很繁琐。 - Matthieu M.inst.CleanupCode()
会更加简单明了,而不是去搞析构函数。我认为这是一个尝试使用RAII来解决错误处理和正常程序执行的情况,只会导致头疼的案例。 - Mark Lakata