在 C++ 中调用可以抛出异常的函数的析构函数;
我知道我不应该抛出异常析构函数。
如果我的析构函数调用了一个可以抛出异常的函数,那么我在析构函数中捕获它并且不再抛出异常可以吗? 或者它是否会导致中止,并且我根本不应该从析构函数中调用此类函数?
I know that I shouldn't throw exceptions from a destructor.
If my destructor calls a function that can throw an exception, is it OK if I catch it in the destructor and don't throw it further? Or can it cause abort anyway and I shouldn't call such functions from a destructor at all?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

发布评论
评论(5)
是的。
查看标准库中的 std::fstream 类作为示例。
- close() 可能会引发异常。
- 析构函数可以调用 close() 但析构函数不会抛出异常(它将吞掉任何异常)。
这个概念是,如果析构函数调用任何可以抛出异常的方法,那么这些方法应该是公共的。 因此,如果对象的用户想要检查异常,他们可以使用公共方法并处理异常。 如果他们不关心异常,那么就让析构函数处理问题。
回到 std::fstream 示例。
{
std::fstream text("Plop");
// Load Text.
// I don't care if the close fails.
// So let the destructor handle it and discard exceptions
}
{
// If this fails to write I should at least warn the user.
// So in this case I will explicitly try and close it.
try
{
std::ofstram password("/etc/password");
// Update the password file.
password.close();
}
catch(...)
{
Message.ShowDialog("You failed to update the Password File");
}
}
如果在传播另一个异常的堆栈展开期间异常离开析构函数,则调用 std::terminate()。
当没有正在进行堆栈展开时,异常可能会在不调用 std::terminate() 的情况下离开析构函数。 但是,对于在堆上分配的对象,这将导致内存泄漏,因为对于从其析构函数中抛出异常的对象,不会调用“operator delete”。 令人惊讶的是,在这种情况下,基类的析构函数仍然被调用: 如果派生类析构函数抛出异常,基类析构函数会发生什么
如果异常在析构函数内部被捕获(以便异常不会离开析构函数),则不会即使另一个异常的堆栈展开正在进行中也会出现问题。 这里更深入地描述了这种情况: http: //bin-login.name/ftp/pub/docs/programming_languages/cpp/cffective_cpp/MEC/MI11_FR.HTM
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
简单的答案,永远不要允许 dtor 的例外!
复杂的答案。 只有当另一个异常处于活动状态时,异常逃脱了 dtor,您才会真正陷入困境。 正常情况是当您已经从另一个异常中展开堆栈并且相关对象被销毁时。 在这种情况下,如果异常逃逸 dtor,则调用
std::terminate
,请注意,您可以通过调用std 为
。std::terminate
放入自己的处理程序::set_terminatestd::terminate
的默认实现是调用 abort。让事情变得更复杂的是,大多数想要对其异常安全性做出任何保证的函数,主要是基本保证或强保证,都依赖于底层类型本身而不是抛出它们的 dtor*
真正的问题是,您的程序会处于什么状态是在什么时候出现这个错误的? 你怎样才能康复? 这个恢复应该在哪里处理? 您需要查看您的具体案例并解决这些问题。 有时捕获异常并忽略它就可以了。 其他时候你需要提出一些危险信号。
所以答案是:C++ 允许在 dtor 中抛出异常,但你不应该允许它逃逸。
*这里有一个简短的 异常保证概要(这里有一个更长的文章)
Simple answer, never allow an exception from a dtor!
The complicated answer. You only get really nailed if the exception escapes the dtor while another exception is active. The normal case for this is when you are already unwinding the stack from another exception and the object in question is destroyed. In that case if the exception escapes the dtor then
std::terminate
is called, note you can put in your own handler forstd::terminate
by callingstd::set_terminate
. The default implementation ofstd::terminate
is to call abort.To complicate things more, most functions that want to make any guarantee about their exception safety, mainly the basic guarantee or the strong guarantee, rely on the underlying types to themselves not throw in their dtor*
The real question is, what state would your program be in when this error occurs? How can you recover? Where should this recovery be handled? You need to look at your specific case and work these issues out. Sometimes it's just fine to catch the exception and ignore it. Other times you need to raise some red flags.
So the answer is: it allowed by C++ to throw an exception in a dtor, but you shouldn't ever allow it to escape.
*Here's a brief synopsis of the exception guarantees (here's a much longer article)