RAII vs. exceptions

Assaf Lavie picture Assaf Lavie · Oct 1, 2008 · Viewed 7.8k times · Source

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.

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.

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.

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.

Appendix

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

Answer

Martin York picture Martin York · Oct 1, 2008

You SHOULD NOT throw an exception out of a destructor.

Note: Updated to refeclt changes in the standard:

In C++03
If an exception is already propagating then the application will terminate.

In C++11
If the destructor is noexcept (the default) then the application will terminate.

The Following is based on C++11

If an exception escapes a noexcept function it is implementation defined if the stack is even unwound.

The Following is based on C++03

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

throwing exceptions out of a destructor

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.

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