RAII与异常 [英] RAII vs. exceptions

查看:143
本文介绍了RAII与异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们在C ++中使用RAII的越多,我们越发现自己使用析构函数来做非平凡的释放。现在,释放(完成,但是你想调用它)可能会失败,在这种情况下,异常真的是让楼上的任何人知道我们的释放问题的唯一方法。但是再次,抛出 - 析构器是一个坏主意,因为在堆栈解开期间抛出异常的可能性。 std :: uncaught_exception()让你知道什么时候发生,但没有更多,因为除了让你记录一个消息之前终止你没有太多可以做,除非你'愿意离开你的程序在一个未定义的状态,其中一些东西被释放/最终和一些不。

The more we use RAII in C++, the more we find ourselves with destructors that do non-trivial deallocation. Now, deallocation (finalization, however you want to call it) can fail, in which case exceptions are really the only way to let anybody upstairs know of our deallocation problem. But then again, throwing-destructors are a bad idea because of the possibility of exceptions being thrown during stack unwinding. std::uncaught_exception() lets you know when that happens, but not much more, so aside from letting you log a message before termination there's not much you can do, unless you're willing to leave your program in an undefined state, where some stuff is deallocated/finalized and some not.

一种方法是有没有抛出的析构函数。但在很多情况下,只是隐藏一个真正的错误。例如,我们的析构函数可能会关闭一些由RAII管理的DB连接,因为抛出了一些异常,并且这些DB连接可能无法关闭。这不一定意味着我们确定程序在这一点终止。另一方面,记录和跟踪这些错误并不是每种情况的真正解决方案;否则我们就没有必要从例外开始。
使用no-throw析构函数,我们也发现自己必须创建reset()函数,这些函数应该在销毁之前被调用 - 但这只是违背了RAII的全部目的。

One approach is to have no-throw destructors. But in many cases that just hides a real error. Our destructor might, for example, be closing some RAII-managed DB connections as a result of some exception being thrown, and those DB connections might fail to close. This doesn't necessarily mean we're ok with the program terminating at this point. On the other hand, logging and tracing these errors isn't really a solution for every case; otherwise we would have had no need for exceptions to begin with. With no-throw destructors we also find ourselves having to create "reset()" functions that are supposed to be called before destruction - but that just defeats the whole purpose of RAII.

另一种方法只是让程序终止,因为它你可以做的最可预测的事情。

Another approach is just to let the program terminate, as it's the most predictable thing you can do.

有些人建议链接异常,以便一次可以处理多个错误。但我真的从来没有实际看到在C + +,我不知道如何实现这样的事情。

Some people suggest chaining exceptions, so that more than one error can be handled at a time. But I honestly never actually seen that done in C++ and I've no idea how to implement such a thing.

所以这是RAII或异常。不是吗?我倾向于no-throw析构函数;主要是因为它保持事情简单(r)。但我真的希望有一个更好的解决方案,因为,正如我所说,我们使用RAII越多,我们发现自己使用dtors,做一些不平凡的事情。

So it's either RAII or exceptions. Isn't it? I'm leaning toward no-throw destructors; mainly because it keeps things simple(r). But I really hope there's a better solution, because, as I said, the more we use RAII, the more we find ourselves using dtors that do non-trivial things.

附录

我添加了指向有趣的主题文章和讨论的链接:

I'm adding links to interesting on-topic articles and discussions I've found:

  • Throwing Destructors
  • StackOverflow discussion on the problems with SEH
  • StackOverflow discussion on throwing-destructors (thanks, Martin York)
  • Joel on Exceptions
  • SEH Considered Harmful
  • CLR Exception Handling which also touches on exception chaining
  • Herb Sutter on std::uncaught_exception and why it's not as useful as you think
  • Historical discussion on the matter with interesting participants (long!)
  • Stroustrup explaining RAII
  • Andrei Alexandrescu's Scope Guard

推荐答案

不得

如果异常已经传播,则应用程序将终止。

You MUST NOT throw an exception out of a destructor.
If an exception is already propagating then the application will terminate.

终止意味着立即停止。堆叠展开停止。没有更多的析构函数被调用。所有坏东西。请参阅此处的讨论。

By terminate I mean stop immediately. Stack unwinding stops. No more destructors are called. All bad stuff. See the discussion here.

http://stackoverflow.com/questions/130117/throwing-exceptions-out-of-a-destructor#130123

我不要跟随(不同意)你的逻辑,这导致析构函数变得更复杂。

正确使用智能指针这实际上使析构函数更简单,因为一切都变得自动。每一个类都有自己的小块的拼图。这里没有脑手术或火箭科学。另一个RAII的大胜利。

I don't follow (as in disagree with) your logic that this causes the destructor to get more complicated.
With the correct usage of smart pointers this actually makes the destructor simpler as everything now becomes automatic. Each class tides up its own little piece of the puzzle. No brain surgery or rocket science here. Another Big win for RAII.

至于std :: uncaught_exception()的可能性,我指向 Herb Sutters文章,说明为什么无法使用

As for the possibility of std::uncaught_exception() I point you at Herb Sutters article about why it does not work

这篇关于RAII与异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆