检测析构函数中的活动异常
我有一个类正在使用 RAII 进行清理,以防出现问题。这意味着该类包含一个标志,该标志告诉它工作是否已完成,如果在调用构造函数时未设置该标志,则它将执行其清理任务并生成日志消息。现在我希望这个类变得更聪明,即它应该找出错误是否发生,因为工作被中止(即抛出异常并调用析构函数)或者因为有人误用了这个类并且从未使用过实际上完成了工作。这意味着我必须在析构函数中找出异常是否处于活动状态。如果找到,我将生成一条日志消息,可能会打印异常的内容,然后重新抛出它。我猜是这样的。
Foo::~Foo () {
try { /* do not know what to put here */ }
catch( const std::exception & ex ) {
// produce error in log
throw;
}
catch( ... ) {
// produce some other log message
throw;
}
}
但是我不确定这是否有效,因为异常在调用析构函数之前就已处于活动状态,并且并非源自 try
块。另外,我在析构函数内使用了 throw; 并在此时抛出异常是一个非常糟糕的想法。所以我不会这样做,除非标准明确保证这种情况是这条规则的例外(没有双关语)(我不知道)。
那么这是否可能,或者我应该以其他方式处理这种情况?
I have a class that is using RAII for cleanup in case something goes wrong. This means the class contains a flag, that tells it whether the work has been completed, and if this flag is not set when the constructor is called it is performing it's cleanup tasks and produces a log messages. Now I would like this class to become one step more clever, i.e. it should find out, if the error happened, because the work was abborted (i.e. an exception was thrown and the destructor got called) or because someone was missusing this class and never actually finished the work. This means I would have to find out in the destructor, if an exception is active. If one is found I would produce a log message, possibly printing the content of the exception and then rethrowing it. I am guessing something like this.
Foo::~Foo () {
try { /* do not know what to put here */ }
catch( const std::exception & ex ) {
// produce error in log
throw;
}
catch( ... ) {
// produce some other log message
throw;
}
}
However I am not sure if this would work at all, since the exception is active already before the destructor is called and does not originate from the try
block. Also I am using a throw;
inside the destructor and throwing an exception at this point is a really bad Idea. So I would not do it, unless the standard guarantees clearly that this case is an exception (no pun intended) to this rule (which I don't know).
So is this possible at all, or should I handle this situation in some other way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您可以使用 std::uncaught_exception() ,如果已引发异常但
catch
尚未处理它,它会返回 true。您可以在析构函数中使用此检查来决定应该做什么或不应该做什么。请注意,良好的编程指南通常规定让析构函数在不同情况下表现明显不同通常不是一个好主意。所以使用这个功能,但不要滥用它。一个常见的用途是让析构函数仅在没有活动的未捕获异常时抛出(此函数返回 false)。但这种行为通常不是好的设计。如果情况严重到需要例外,那么可能不应该被忽视。并且析构函数无论如何都不应该抛出异常。
例子:
You can use
std::uncaught_exception()
which returns true if an exception has been thrown but acatch
has not yet handled it. You can use this check in your destructor to make decisions about what it should or should not do.A note of caution, good programming guidelines usually dictate that having your destructor behave significantly differently under different circumstances is usually not a good idea. So use this function, but don't abuse it. A common use is to have a destructor that only throws if there is no active uncaught exception (this function returns false). But that type of behavior is generally not good design. If the condition was bad enough to warrant an exception, it probably shouldn't be ignored. And destructors should not throw exceptions anyways.
Example:
无法使用
bool std::uncaught_exception()
正确,因此它在 C++20 中被删除。我们现在有了int std::uncaught_exceptions()
。您需要调用它两次:事先一次(例如在构造函数中),然后在析构函数中再次调用。如果第二次调用返回一个更大的数字,则意味着析构函数因异常而被调用。否则它将返回相同的数字。
There was no way to use
bool std::uncaught_exception()
correctly, so it was removed in C++20. We now haveint std::uncaught_exceptions()
.You need to call it twice: once beforehand (e.g. in the constructor), then again in the destructor. If the second call returned a larger number, it means the destructor was called due to an exception. Otherwise it will return the same number.
这是不可能以安全的方式进行的。
您可以做的是检查析构函数中的参数,这应该可以判断处理是否已完成。
顺便说一句,为什么不将错误记录在可以实际处理错误的 catch 块中?您应该知道处理已因错误而终止。
It is not possible to do in a safe manner.
What you can do is to check your parameters in the destructor, and that should tell if the processing was completed.
By the way, why are you not logging the error in the catch block where you can actually handle the error? There you should know that the processing was terminated with the error.
看看这个我的问题和回复< /a>.
基本上,您可以在第一个 try 块中使用简单的
throw
重新抛出当前活动的异常。但是,只有当您确定当前正在处理异常时,这才是安全的,即从catch
块内调用析构函数。否则,>throw
将调用std::terminate()
。然而,从析构函数中抛出异常是不受欢迎的,所以我不会在之后重新抛出异常。毕竟,整件事对我来说看起来并不是一个好主意。
异常处理模式很好,但我不会在不相关的析构函数中执行它。再次,请参阅引用的问题。
Have a look at this question of mine and the responses.
Basically, you can rethrow the currently active exception using a simple
throw
in the first try block. However, this is only safe if you know for sure that there is an exception currently being handled, i.e the destructor is called from within acatch
block. Otherwise, thethrow
will invokestd::terminate()
.However, throwing exceptions from within destructors is frowned upon, so I wouldn't rethrow the exceptions afterwards. Atfer all, the whole thing doesn't look like a good idea to me.
The exception handling pattern is fine, but I wouldn't do it in an unrelated destructor. Again, see the referenced question.