Reasoning behind C++ active exception mechanism - c++

I recently learned that in C++ there is a single "slot" for an active exception and this raise some questions for me.
The example that I know is something like:
void f()
{
MyClass c;
throw MyException;
}
When we get to the throw the function immediately returns and then the exception starts looking for its matching catch. But let's say that during the return of f, when the destructor of c is called, suppose it throws another exception of type MyException2, in this case from what I understood the program always crashes because there is only one "slot" for an active exception so when MyException2 occurs there is a problem.
I would like to know if there is a reason for this specific approach since most other languages have some sort of stack and give a message like During handling of this exception this other exception occurred, with clear stack traces for both exceptions.
Is there a reason for this problem not being approached? Things like a stack of active exceptions and if MyException2 occurs while MyException1 is active then it will just resolve and then return to the handling of MyException1?
I'm sorry if I may not be familiar with the proper terms, this is a purely education question from someone who wishes to know more about the "guts" of the language out of pure fascination.

What you’re thinking about in, say, Python looks like
try: risky()
except Error as e:
some_cleanup(e)
also_risky() # raises OtherError
if still_unhappy(): raise
more_handling()
The corresponding code in C++ behaves the same way and does not automatically terminate:
try {risky();}
catch(const Error &e) {
some_cleanup(e);
also_risky(); // throws OtherError
if(still_unhappy()) throw;
more_handling();
}
The reason is that the original exception might or might not have been handled successfully (is more_handling necessary, or is it just part of retrying?). C++ makes the optimistic statement that it was, whereas by default Python 3 makes the pessimistic statement that the new exception is fallout from the old. C++ could of course provide a syntax to indicate the other choice, like Python does (raise new from None), but such an “associated exception” would be more difficult still to deal with in a static-typing context than exceptions already are, and one of the main motivations is absent since C++ expects the program to provide whatever backtrace-reporting mechanisms are desired.
The parallel is stronger if you consider destructors in both languages (especially in CPython where many of them are reliably invoked during stack unwinding): here, Python simply prints to standard error if a destructor throws, because to do otherwise would greatly complicate its internal resource management. C++ is actually more permissive in that a destructor can throw so long as it was not invoked directly by the unwinding mechanism; this is dangerous, but is occasionally used by experts to good effect. On the other hand, C++ most certainly does not consider writing to standard error a sufficient option for handling an exception, so if its resource management encounters such a problem, it’s all over.

Related

In C++, Is it possible to force the user to catch exceptions?

In short, is it possible to get C++ to force the invoker of a method to put a try...catch block?
(To clarify:
I don't necessarily mean the immediate invoker, I mean forcing the fact that it's caught somewhere. Also, I'm talking about forcing at compile time.)
The long:
I've read that it not recommended to use exception specification and that it doesn't work properly anyway (http://4thmouse.com/mystuff/articles/UsingExceptionsEffectively.html)
But the general consensus seems to favor the use of exceptions to return errors over the user of writing methods that return error codes.
So if I'm writing say a library, what's to stop the user from calling my method without putting any try...catch blocks, and then getting his program crashing when my code throws an exception?
(To be clear, I only require the exception to be caught somewhere in the users stack, not necessarily in the immediate calling code, and the compiler to complain if this is not the case.)
No, it is not.
Indeed, there is no mechanism to force the caller of a function (anywhere in the call stack) to handle any kind of error. At least, not via a compilation failure. Return values can be discarded. Even bundling error codes with return values (via expected<T, E>) doesn't issue a compile-time error if the user doesn't actually check to see if the value is available before fetching it.
C++17 may give us the [[nodiscard]] attribute, which allows compilers to issue a warning if a return value (presumably an error code) is discarded by the caller. But a compile-time warning will be as close as you can get.
In short, is it possible to get C++ to force the invoker of a method
to put a try...catch block?
No. This would defeat the whole purpose of exceptions. Exceptions are specifically made for the use case of propagating errors across multiple layers without the intermediate layers being aware of them.
Let's say you have a call hierarchy like A -> B -> C -> D -> E, and an error occurs in E. A can handle the error. B, C and D do not need to be aware of the error at all. This is exactly what exceptions are good for!
If you want to return an error directly to the caller because handling the error is indeed the caller's concern, then an exception is often the wrong design and a return value might be the better choice.
"Enforced" exceptions of a certain form have been tried in Java, but I'd consider it a failed experiment, as it usually results in code like this:
try {
method();
} catch (SomeCheckedException ex) {
// ignore
}
That C++ does not encourage this should be considered a feature.
I've read that it not recommended to use exception specification and
that it doesn't work properly anyway
Exactly. The only exception specification which was ever useful and which worked was throw() to signal that no exception at all is thrown, and that one has been superseded in C++11 by noexcept.
But the general consensus seems to favor the use of exceptions to
return errors over the user of writing methods that return error
codes.
See above. It depends on whether you want an error to propagate or if the caller can and should handle it.
So if I'm writing say a library, what's to stop the user from calling
my method without putting any try...catch blocks, and then getting his
program crashing when my code throws an exception?
A library which requires its user to surround all function calls with try blocks has a bad interface and should be redesigned, accordingly.
Also... you assume that a "program" will use your library. But this assumption will not always be true. The library client may itself be a library. There may be a lot of different library layers between the program and your library. You use exceptions if you do not care which layer handles them.
There's a general consensus? Not that I'm aware of. As for the exceptions, no. The compiler cannot enforce that somebody catches the exception somewhere up the call stack. At compile time, the compiler has no idea who may be calling your function, and your function may throw any arbitrary exception, as may any function that your function calls. The linker might have a chance, but it would have to maintain a lot of extra information dealing with what exceptions a function may throw, as well as what exceptions a function may catch. This gets even uglier when you start to talk about dynamically loaded libraries (DLL/.so) as that would have to get resolved at runtime.

Catching exceptions in destructors

Is it possible to make a destructor catch exceptions and then re-throw them?
If so, how would I do that, since there isn't a clear place for a try statement?
Basically, I want to ideally do:
CMyObject::~CMyObject()
{
catch(...) // Catch without a try. Possible?
{
LogSomeInfo();
throw; // re-throw the same exception
}
// Normal Destructor operations
}
Background
I have a large, complex application that is throwing an unhandled exception somewhere.
I don't have easy access to main or the top level message-pump or anything similar, so there's no easy place to catch all unhandled exceptions.
I figure any unhandled exception has to pass through a bunch of destructors as the stack is unwound. So, I'm contemplating scattering a bunch of catch statements in destructors. Then at least I'd know what objects are in play when the exception is thrown. But I have no idea if this is possible, or advisable.
EDIT: You can use std::uncaught_exception to check if an exception is currently being thrown (i.e. if stack unwinding is in progress due to an exception). It is not possible to catch that exception or otherwise get access to it from your destructor. So if your logging doesn't need access to the exception itself, you can use
CMyObject::~CMyObject()
{
if(std::uncaught_exception()) {
LogSomeInfo(); // No access to exception.
}
// Normal Destructor operations
}
Note that this question was asked in 2013, meanwhile std::uncaught_exception was replaced with std::uncaught_exceptions (notice the additional s at the end) which returns an int. For a rationale, see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4152.pdf, so if you are using C++17, you should prefer the new version. The above paper also explains why the old std::uncaught_exception will not work as expected in some situations.
Another option might be std::set_terminate. This is useful if you want to have a method called when an exception is not caught and about to terminate the program. In the terminate handler, I usually print some information about the exception and a (demangled) backtrace of where it originates from to my log file before finally terminating the program. This is compiler and system specific, but a real helper as it saves a lot of time if you write server processes and often the log file is all you get from ops.
You can use std::uncaught_exception() which returns true if and only if there is an exception being processed. It has been available since C++98, and is superseded by std::current_exception which returns a std::exception_ptr.
However you must be careful not to throw another exception in an unguarded context, otherwise std::terminate will be caught. Example:
X::~X() {
if (std::uncaught_exception()) {
try {
LogSomeInfo();
// and do something else...
} catch(...) {}
}
}
A destructor cannot catch the exception that is causing the destruction of the instance.
You can only know if there is any "active exception" (see uncaught_exception) during the destruction (or, in C++17, how many of them there are there with uncaught_exceptions) but it's possible that the exception(s) are indeed going to be handled after that.
Dealing with exceptions is very hard, much harder than someone may think at a first sight and the reason is that exception safety doesn't scale by composition. This in my opinion means that is basically impossible to have non trivial stateful subsystems with strong exception safety (in case of an exception being thrown nothing happened to the internal state). This was discovered long ago (see 1994 Tom Cargill's "Exception handling: A False Sense of Security") but apparently is still ignored by large part of the C++ community.
The only reasonable way to handle exceptions I can think to is to have subsystems with clear well defined interfaces with thick "walls" (no side effect happening inside may escape), and that can be re-initialized to a well known state from scratch if needed when something goes wrong. This not trivial but can be done correctly to a reasonable extent.
In all other cases the global state of the system when an exception is caught is indefinite at best at the point of catch and there are in my opinion few use cases in which you can do anything in such a condition except dying immediately as loudly as possible instead of taking further actions without indeed knowing what is going on (dead programs tell no lie). Even keeping on calling destructors is somewhat questionable in my opinion.
Or you may try to be as functional as possible, but that's not an easy path either (at least for my brain) and it's also moving far away from reality (most computers are mutable objects with many billions of bits of mutable state: you can pretend this is not the case and they're instead mathematical functions with no state and with predictable output dependent on input... but in my opinion you're just deluding yourself).

C++ exception specification replacement

I have realized, after some reading, that in C++ the exceptions specification is considered a bad thing:
int f() throw(A, B); // bad because a lot of reasons
(some references: 1, 2, etc.)
What I have not understood is how to replace it. How can I tell to the f()'s caller that he must catch an exception?
How about
//throws: A if something is wrong
// B if something else is wrong
int f();
You don't. Not saying anything means it can throw anything.
I assume you have some Java background to ask this question. Compile-time exception checking was a Java experiment that failed. That's why you don't see it anywhere else.
The general rule for exception handling is: handle it where you can. This usually boils down to a try-catch at some very high level, where you basically tell the user whatever he was trying to do failed. It is very rare to be able to recover from an exception and continue the operation.
You should, of course, provide documentation what exceptions your function throws. I don't consider this to be a replacement for the throw specification (its purpose is very different). You should document the exceptions that your function throws and can be handled meaningfully by the caller, whereas the throw specification has to list any exceptions that may come out of this function (and the functions it calls).
You could replace it with an automated documentation tool.
Such tools often have the ability to nicely format which exceptions a method will throw, like the doxygen \exception command (or \throw or \throws). Assuming users of your code read documentation, they would be able to find out what exceptions to catch.
/**
* #exception A
* #exception B
*/
int f();
See this question for more useful info: How to document all exceptions a function might throw?
How can I tell to the f()'s caller that he must catch an exception?
That you think the caller must catch an exception indicates that there might be something wrong with your design. Are you using exceptions to signal a non-exceptional circumstance such as end of file?
Mandating the immediate callers to catch all possible exceptions is bad design. Example: The push_back member functions of the standard library containers allocate memory, which can fail. The designers of the library did not expect callers to wrap each and every push_back in a try/catch block. It doesn't make sense. Doing so would make the code much uglier, much harder to test. Besides, how would you recover from an out of memory condition? Handling this once, at a high level, is about all you can do.

Should C++ exceptions provide additional details besides what()

Should my exception classes provide details in public fields in addition to what()?
Consider for example boost::property_tree::ptree_bad_path which might give a message:
"No such node (mynode.value1)"
The only way to access the path ("mynode.value1") is by parsing the string. Is there an argument against adding additional public fields to carry such information, that is:
class ptree_bad_path : public ptree_error {
public:
const std::string path; // <- additional detail by public field
....
Are there drawbacks to this approach?
In theory, you run the risk of having your program terminate if you ever have two unhandled exceptions at the same time. This is, however, a rather rare situation.
Throwing during the preparation of the exception: fine (though you won't get the exception you expected)
Throwing during the copy of the exception (often elided, avoidable): crash
Throwing during the unwinding: crash
Throwing during the handling of the exception (catch): fine (after all, rethrowing a different exception is common)
So, the avoidable risk here is if the copy constructor of your exception might happen to throw. It is trivial to elude the issue by moving the state off to a shared_ptr contained within the exception. It makes copies a bit "special" (since they share their state with the original) but if it's documented properly it should not cause any grief.
The greater risk is during stack unwinding. It only occurs if a destructor throws, though.
Personally, the exceptions I use contain:
an error code (for the API to display/encode properly, all error messages are mapped to a code, it helps in Chinese/Korean/Japanese, really)
a log message, with some details (ID/name of the item that cause the issue, original error when translating another exception, whatever helps!)
the function/file/line at which the exception was thrown
the time at which the exception thrown
additional notes (appended "on the fly" during stack unwinding)
a complete backtrace (using Linux specific functions)
The only controversial point here is the on the fly bit, since it might effectively crash. On the other hand, I work on servers so crashes are easily (and urgently) fixed and for the last 5 years I was careful enough not to cause a crash (this way ;)).
Note that this scheme is obviously only available if you use exceptions sparsely. If you routinely throw a dozen exceptions per task, the performance might be unnacceptable. On the other hand, the Zero Cost model used by major compilers already harshly penalize the exceptional path so...
Your exception class should contain all the information required to handle the error. This usually means tagging it with what went wrong and any context necessary. It is a good idea to store the path in your exception class.
Are there drawbacks to this approach?
Try to avoid having the members themselves throw as they will call std::terminate.
This is just my opinion, but if you're going to throw an exception you might want to make sure it has enough information for you to know (a) what caused the exception, and (b) where the exception was thrown.
You are probably (hopefully) not going to show the exception to the end user, so therefore logging the exception becomes something that purely enables/improves supportability. So from a development perspective, you basically want to be in a position where you know as much as possible about what happened.
Of course you're right in that you are walking a fine wire here. You don't want to have such complex code in your exception handling that it runs the risk of throwing its own exception!
Your exceptions may carry as much information as their catchers are ready (and willing) to use. If your particular application can use this additional information, you can write your own exception classes with peace of mind. In any case, all exception classes should inherit from std::exception to ensure that catch clauses not expecting custom exceptions will work correctly.
A different issue is exposing those classes on a library to be used by third party clients. In this case you should consider carefully whether the benefits of this additional information outweight the hassle introduced by the additional interface and even the possibility that it may not be used at all.
EDIT: As Pubby says, your exception classes should never throw to avoid unwelcome calls to std::terminate(). In general, no exception-related code should ever throw, and this includes destructors for any class.

RAII vs. exceptions

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:
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 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
From the original question:
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
Failure to cleanup a resource either indicates:
Programmer error, in which case, you should log the failure, followed by notifying the user or terminating the application, depending on application scenario. For example, freeing an allocation that has already been freed.
Allocator bug or design flaw. Consult the documentation. Chances are the error is probably there to help diagnose programmer errors. See item 1 above.
Otherwise unrecoverable adverse condition that can be continued.
For example, the C++ free store has a no-fail operator delete. Other APIs (such as Win32) provide error codes, but will only fail due to programmer error or hardware fault, with errors indicating conditions like heap corruption, or double free, etc.
As for unrecoverable adverse conditions, take the DB connection. If closing the connection failed because the connection was dropped -- cool, you're done. Don't throw! A dropped connection (should) result in a closed connection, so there's no need to do anything else. If anything, log a trace message to help diagnose usage issues. Example:
class DBCon{
public:
DBCon() {
handle = fooOpenDBConnection();
}
~DBCon() {
int err = fooCloseDBConnection();
if(err){
if(err == E_fooConnectionDropped){
// do nothing. must have timed out
} else if(fooIsCriticalError(err)){
// critical errors aren't recoverable. log, save
// restart information, and die
std::clog << "critical DB error: " << err << "\n";
save_recovery_information();
std::terminate();
} else {
// log, in case we need to gather this info in the future,
// but continue normally.
std::clog << "non-critical DB error: " << err << "\n";
}
}
// done!
}
};
None of these conditions justify attempting a second kind of unwind. Either the program can continue normally (including exception unwind, if unwind is in progress), or it dies here and now.
Edit-Add
If you really want to be able to keep some sort of link to those DB connections that can't close -- perhaps they failed to close due to intermittent conditions, and you'd like to retry later -- then you can always defer cleanup:
vector<DBHandle> to_be_closed_later; // startup reserves space
DBCon::~DBCon(){
int err = fooCloseDBConnection();
if(err){
..
else if( fooIsRetryableError(err) ){
try{
to_be_closed.push_back(handle);
} catch (const bad_alloc&){
std::clog << "could not close connection, err " << err << "\n"
}
}
}
}
Very not pretty, but it might get the job done for you.
You're looking at two things:
RAII, which guarantees that resources are cleaned up when scope is exited.
Completing an operation and finding out whether it succeeded or not.
RAII promises that it will complete the operation (free memory, close the file having attempted to flush it, end a transaction having attempted to commit it). But because it happens automatically, without the programmer having to do anything, it doesn't tell the programmer whether those operations it "attempted" succeeded or not.
Exceptions are one way to report that something failed, but as you say, there's a limitation of the C++ language that means they aren't suitable to do that from a destructor[*]. Return values are another way, but it's even more obvious that destructors can't use those either.
So, if you want to know whether your data was written to disk, you can't use RAII for that. It does not "defeat the whole purpose of RAII", since RAII will still try to write it, and it will still release the resources associated with the file handle (DB transaction, whatever). It does limit what RAII can do -- it won't tell you whether the data was written or not, so for that you need a close() function that can return a value and/or throw an exception.
[*] It's quite a natural limitation too, present in other languages. If you think RAII destructors should throw exceptions to say "something has gone wrong!", then something has to happen when there's already an exception in flight, that is "something else has gone wrong even before that!". Languages that I know that use exceptions don't permit two exceptions in flight at once - the language and syntax simply don't allow for it. If RAII is to do what you want, then exceptions themselves need to be redefined so that it makes sense for one thread to have more than one thing going wrong at a time, and for two exceptions to propagate outward and two handlers to be called, one to handle each.
Other languages allow the second exception to obscure the first, for example if a finally block throws in Java. C++ pretty much says that the second one must be suppressed, otherwise terminate is called (suppressing both, in a sense). In neither case are the higher stack levels informed of both faults. What is a bit unfortunate is that in C++ you can't reliably tell whether one more exception is one too many (uncaught_exception doesn't tell you that, it tells you something different), so you can't even throw in the case where there isn't already an exception in flight. But even if you could do it in that case, you'd still be stuffed in the case where one more is one too many.
It reminds me a question from a colleague when I explained him the exception/RAII concepts: "Hey, what exception can I throw if the computer's switched off?"
Anyway, I agree with Martin York's answer RAII vs. exceptions
What's the deal with Exceptions and Destructors?
A lot of C++ features depend on non-throwing destructors.
In fact, the whole concept of RAII and its cooperation with code branching (returns, throws, etc.) is based on the fact deallocation won't fail. In the same way some functions are not supposed to fail (like std::swap) when you want to offer high exception guarantees to your objects.
Not that it doesn't mean you can't throw exceptions through destructors. Just that the language won't even try to support this behaviour.
What would happen if it was authorized?
Just for the fun, I tried to imagine it...
In the case your destructor fails to free your resource, what will you do? Your object is probably half destructed, what would you do from an "outside" catch with that info? Try again? (if yes, then why not trying again from within the destructor?...)
That is, if you could access your half-destructed object it anyway: What if your object is on the stack (which is the basic way RAII works)? How can you access an object outside its scope?
Sending the resource inside the exception?
Your only hope would be to send the "handle" of the resource inside the exception and hoping code in the catch, well... try again to deallocate it (see above)?
Now, imagine something funny:
void doSomething()
{
try
{
MyResource A, B, C, D, E ;
// do something with A, B, C, D and E
// Now we quit the scope...
// destruction of E, then D, then C, then B and then A
}
catch(const MyResourceException & e)
{
// Do something with the exception...
}
}
Now, let's imagine for some reason the destructor of D fails to deallocate the resource. You coded it to send an exception, that will be caught by the catch. Everything goes well: You can handle the failure the way you want (how you will in a constructive way still eludes me, but then, it is not the problem now).
But...
Sending the MULTIPLE resources inside the MULTIPLE exceptions?
Now, if ~D can fail, then ~C can, too. as well as ~B and ~A.
With this simple example, you have 4 destructors which failed at the "same moment" (quitting the scope). What you need is not not a catch with one exception, but a catch with an array of exceptions (let's hope the code generated for this does not... er... throw).
catch(const std::vector<MyResourceException> & e)
{
// Do something with the vector of exceptions...
// Let's hope if was not caused by an out-of-memory problem
}
Let's get retarted (I like this music...): Each exception thrown is a different one (because the cause is different: Remember that in C++, exceptions need not derive from std::exception). Now, you need to simultaneously handle four exceptions. How could you write catch clauses handling the four exceptions by their types, and by the order they were thrown?
And what if you have multiple exceptions of the same type, thrown by multiple failed deallocation? And what if when allocating the memory of the exception arrays of arrays, your program goes out of memory and, er... throw an out of memory exception?
Are you sure you want to spend time on this kind of problem instead of spending it figuring why the deallocation failed or how to react to it in another way?
Apprently, the C++ designers did not see a viable solution, and just cut their losses there.
The problem is not RAII vs Exceptions...
No, the problem is that sometimes, things can fail so much that nothing can be done.
RAII works well with Exceptions, as long as some conditions are met. Among them: The destructors won't throw. What you are seeing as an opposition is just a corner case of a single pattern combining two "names": Exception and RAII
In the case a problem happens in the destructor, we must accept defeat, and salvage what can be salvaged: "The DB connection failed to be deallocated? Sorry. Let's at least avoid this memory leak and close this File."
While the exception pattern is (supposed to be) the main error handling in C++, it is not the only one. You should handle exceptional (pun intended) cases when C++ exceptions are not a solution, by using other error/log mechanisms.
Because you just met a wall in the language, a wall no other language that I know of or heard of went through correctly without bringing down the house (C# attempt was worthy one, while Java's one is still a joke that hurts me on the side... I won't even speak about scripting languages who will fail on the same problem in the same silent way).
But in the end, no matter how much code you'll write, you won't be protected by the user switching the computer off.
The best you can do, you already wrote it. My own preference goes with a throwing finalize method, a non-throwing destructor cleaning resources not finalized manually, and the log/messagebox (if possible) to alert about the failure in the destructor.
Perhaps you're not putting up the right duel. Instead of "RAII vs. Exception", it should be "Trying to freeing resources vs. Resources that absolutely don't want to be freed, even when threatened by destruction"
:-)
One thing I would ask is, ignoring the question of termination and so on, what do you think an appropriate response is if your program can't close its DB connection, either due to normal destruction or exceptional destruction.
You seem to rule out "merely logging" and are disinclined to terminate, so what do you think is the best thing to do?
I think if we had an answer to that question then we would have a better idea of how to proceed.
No strategy seems particularly obvious to me; apart from anything else, I don't really know what it means for closing a database connection to throw. What is the state of the connection if close() throws? Is it closed, still open, or indeterminate? And if it's indeterminate, is there any way for the program to revert to a known state?
A destructor failing means that there was no way to undo the creation of an object; the only way to return the program to a known (safe) state is to tear down the entire process and start over.
What are the reasons why your destruction might fail? Why not look to handling those before actually destructing?
For example, closing a database connection may be because:
Transaction in progress. (Check std::uncaught_exception() - if true, rollback, else commit - these are the most likely desired actions unless you have a policy that says otherwise, before actually closing the connection.)
Connection is dropped. (Detect and ignore. The server will rollback automatically.)
Other DB error. (Log it so we can investigate and possibly handle appropriately in the future. Which may be to detect and ignore. In the meantime, try rollback and disconnect again and ignore all errors.)
If I understand RAII properly (which I might not), the whole point is its scope. So it's not like you WANT transactions lasting longer than the object anyway. It seems reasonable to me, then, that you want to ensure closure as best you can. RAII doesn't make this unique - even without objects at all (say in C), you still would try to catch all error conditions and deal with them as best as you can (which is sometimes to ignore them). All RAII does is force you to put all that code in a single place, no matter how many functions are using that resource type.
You can tell whether there is currently an exception in flight (e.g. we are between the throw and catch block performing stack unwinding, perhaps copying exception objects, or similar) by checking
bool std::uncaught_exception()
If it returns true, throwing at this point will terminate the program, If not, it's safe to throw (or at least as safe as it ever is). This is discussed in Section 15.2 and 15.5.3 of ISO 14882 (C++ standard).
This doesn't answer the question of what to do when you hit an error while cleaning up an exception, but there really aren't any good answers to that. But it does let you distinguish between normal exit and exceptional exit if you wait to do something different (like log&ignore it) in the latter case, rather than simply panicing.
If one really needs to deal with some errors during the finalization process, it should not be done within the destructor. Instead, a separate function that returns an error code or may throw should be used instead. To reuse the code, you can call this function inside the destructor, but you must not allow the exception to leak out.
As some people mentioned, it is not really resource deallocation, but something like resource commit during exit. As other people mentioned, what can you do if saving fails during a forced power-off? There are probably no all-satisfying answers, but I would suggest one of the following approaches:
Just allow the failure and loss to happen
Save the unsaved part to somewhere else and allow the recovery to happen later (see the other approach if this does not work either)
If you do not like either of this approaches, make your user explicitly save. Tell them not to rely on the auto-save during a power-off.