我知道,如果在析构函数中抛出异常,程序会在堆栈展开期间中止执行,因为那时将传播超过1个异常。
这里有一个带注释的示例来演示这一点:
然而,我有一个类层次结构,在其中一个析构函数调用可能引发异常的函数时,由于入口层次结构被污染,现在所有析构函数都标记为
尽管编译器可以插入异常代码,但对于这些类的用户来说,这并不可行,因为它不能阻止程序在上述代码样例中发生异常而导致中止。
因为我希望析构函数是异常安全的,所以我想到将它们全部标记为
同样的示例,但重新设计以避免中止情况,并使析构函数具备异常安全性:
这里有一个带注释的示例来演示这一点:
class Foo
{
public:
~Foo()
{
ReleaseResources();
}
private:
int* pInt;
void ReleaseResources()
{
if (!pInt)
throw 0;
else delete pInt;
}
};
int main() try
{
{
Foo local;
throw 1;
} // aborting here, because now 2 exceptions are propagating!
return 0;
}
catch (int& ex)
{
return ex;
}
然而,我有一个类层次结构,在其中一个析构函数调用可能引发异常的函数时,由于入口层次结构被污染,现在所有析构函数都标记为
noexcept(false)
。尽管编译器可以插入异常代码,但对于这些类的用户来说,这并不可行,因为它不能阻止程序在上述代码样例中发生异常而导致中止。
因为我希望析构函数是异常安全的,所以我想到将它们全部标记为
noexcept
,但要像这样处理可能出现的异常:同样的示例,但重新设计以避免中止情况,并使析构函数具备异常安全性:
class Foo
{
public:
~Foo() noexcept
{
try
{
ReleaseResources();
}
catch (int&)
{
// handle exception here
return;
}
}
private:
int* pInt;
void ReleaseResources()
{
if (!pInt)
throw 0;
else delete pInt;
}
};
int main() try
{
{
Foo local;
throw 1;
} // OK, not aborting here...
return 0;
}
catch (int& ex)
{
return ex;
}
问题是,处理析构函数内部异常的这种常规方法是否正常?是否存在可能导致此设计失败的示例?
主要目标是具有异常安全的析构函数。
另外一个问题是,在第二个示例中,在堆栈展开期间仍然有2个异常传播,为什么没有调用abort?如果只允许在堆栈展开期间出现一个异常?
COM
中的Release()
。我无法控制该函数,我只知道它可能会抛出异常。因此,如果程序在不应该干净地关闭但需要继续运行时,如果该函数抛出异常,则可能记录问题并手动中止是解决问题的方法? - metablaster