C++ 的方式抛出特定异常时析构函数跳过工作?
我在堆栈上有一个对象,我希望其析构函数在调用析构函数时跳过一些工作,因为由于通过堆栈上对象的范围抛出特定异常,堆栈正在展开。
现在我可以在堆栈项的范围内添加一个 try catch 块并捕获有问题的异常并通知堆栈对象不要运行要跳过的工作,然后重新抛出异常,如下所示:
RAII_Class pending;
try {
doSomeWorkThatMayThrowException();
} catch (exceptionToSkipPendingDtor &err) {
pending.notifySkipResourceRelease();
throw;
}
但是,我希望有一种更优雅的方式来做到这一点。例如想象一下:
RAII_Class::~RAII_Class {
if (detectExceptionToSkipPendingDtorBeingThrown()) {
return;
}
releaseResource();
}
I have an object on the stack for which I wish its destructor to skip some work when the destructor is being called because the stack is being unwound due to a specific exception being thrown through the scope of the object on the stack.
Now I could add a try catch block inside the scope of the stack item and catch the exception in question and notify the stack object to not run the work to be skipped an then rethrow the exception as follows:
RAII_Class pending;
try {
doSomeWorkThatMayThrowException();
} catch (exceptionToSkipPendingDtor &err) {
pending.notifySkipResourceRelease();
throw;
}
However, I'm hoping there is a more elegant way to do this. For example imagine:
RAII_Class::~RAII_Class {
if (detectExceptionToSkipPendingDtorBeingThrown()) {
return;
}
releaseResource();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
您几乎可以使用 std::uncaught_exception() 来做到这一点,但不完全是。
Herb Sutter 比我更好地解释了“几乎”:http://www.gotw.ca/ gotw/047.htm
在某些极端情况下,从析构函数调用时
std::uncaught_exception()
返回 true,但相关对象实际上并未被堆栈展开过程销毁。没有 RAII 可能会更好,因为它与您的用例不匹配。 RAII 意味着始终清理;例外与否。
您想要的要简单得多:仅在未引发异常时才释放资源,这是一个简单的函数序列。
You can almost do this with
std::uncaught_exception()
, but not quite.Herb Sutter explains the "almost" better than I do: http://www.gotw.ca/gotw/047.htm
There are corner cases where
std::uncaught_exception()
returns true when called from a destructor but the object in question isn't actually being destroyed by the stack unwinding process.You're probably better off without RAII because it doesn't match your use case. RAII means always clean up; exception or not.
What you want is much simpler: only release resource if an exception is not throw which is a simple sequence of functions.
我会用另一种方式来做——如果没有抛出异常,明确地告诉它去做它的工作:
I would do it the other way around - explicitly tell it to do its work if no exception was thrown:
这似乎是规避使用 RAII 的主要原因。 RAII 的要点是,如果代码中间发生异常,您仍然可以正确释放资源/销毁资源。
如果这不是您想要的语义,则不要使用 RAII。
因此,不要:
只是这样做:
如果中间的代码抛出异常,则资源将不会被释放。这就是您想要的,而不是保留 RAII(并保留名称)但不实现 RAII 语义。
This seems to circumvent the main reason to use RAII. The point of RAII is that if an exception happens in the middle of your code you can still release resources/be destructed properly.
If this isn;t the semantic you want, then don't use RAII.
So instead of:
Just do:
If the code in the middle throws, the resource won't be freed. This is what you want, rather than keeping RAII (and keeping the name) but not implementing RAII semantics.
看起来像 bool std::uncaught_exception();如果您希望对每个异常(而不仅仅是特殊异常)都有这种行为,那么就可以实现这一点!
Looks like bool std::uncaught_exception(); does the trick if you want to have this behavior for every exception, not just special ones!
您可以不使用 try-catch:
或者,您可以使用 RAII 更努力地尝试:
You can do without a try-catch:
Alternatively, you can try a little harder with RAII:
虽然这充其量只是一个拼凑,但如果您拥有您感兴趣的异常类的代码,您可以向该类添加一个静态数据成员(bool),该成员将在对象的构造函数中设置为“true”该类的值,析构函数中为 false(可能需要是您递增/递减的 int)。然后在 RAII 类的析构函数中,您可以检查 std::uncaught_exception(),如果为 true,则查询异常类中的静态数据成员。如果返回 true(或 > 0),则说明您遇到了这些异常之一,否则您将忽略它。
不是很优雅,但它可能会达到目的(只要你没有多个线程)。
Although it would be a kludge at best, if you own the code for the exception class you're interested in, you could add a static data member to that class (bool) that would be set to "true" in the constructor for objects of that class, and false in the destructor (might need to be an int that you increment/decrement instead). Then in the destructor of your RAII class, you can check std::uncaught_exception(), and if true, query the static data member in your exception class. If you get true (or > 0) back, you've got one of those exceptions--otherwise you ignore it.
Not very elegant, but it would probably do the trick (as long as you don't have multiple threads).
我发现这个网站有一个关于 std::uncaught_exception() 的有趣讨论,以及您问题的替代解决方案,对我来说似乎更加优雅和正确:
http://www.gotw.ca/gotw/047.htm
通过这种方式,你的析构函数只做一件事,并且可以防止在一个例外(我认为这是您要解决的问题)。
I found this website with an interesting discussion about std::uncaught_exception() and an alternative solution to your question that seems much more elegant and correct to me:
http://www.gotw.ca/gotw/047.htm
In this way you're destructor does only one thing and you're protected against throwing an exception during an exception (which I assume is the problem you're trying to solve).