Most people say never throw an exception out of a destructor - doing so results in undefined behavior. Stroustrup makes the point that "the vector destructor explicitly invokes the destructor for every element. This implies that if an element destructor throws, the vector destruction fails... There is really no good way to protect against exceptions thrown from destructors, so the library makes no guarantees if an element destructor throws" (from Appendix E3.2).

This article seems to say otherwise - that throwing destructors are more or less okay.

So my question is this - if throwing from a destructor results in undefined behavior, how do you handle errors that occur during a destructor?

If an error occurs during a cleanup operation, do you just ignore it? If it is an error that can potentially be handled up the stack but not right in the destructor, doesn't it make sense to throw an exception out of the destructor?

"Two exceptions at once" is a stock answer but it's not the REAL reason. The real reason is that an exception should be thrown if and only if a function's postconditions cannot be met. The postcondition of a destructor is that the object no longer exists. This can't not happen. Any failure-prone end-of-life operation must therefore be called as a separate method before the object goes out of scope (sensible functions normally only have one success path anyway).
–
spraffAug 30 '11 at 10:13

3

It should catch and handle all exceptions (discarding may be acceptable) OR it should rewrite its post-condition to say "if the input does not satisfy X, the output is Y/undefined"
–
spraffOct 4 '11 at 8:07

6

@spraff: Are you aware that what you said implies "throw away RAII"?
–
KosOct 26 '11 at 13:30

2

@spraff: having to call "a separate method before the object goes out of scope" (as you wrote) actually throws away RAII! Code using such objects will have to ensure that such a method will be called before the destructor is called.. Finally, this idea does not help at all.
–
FrunsiAug 8 '12 at 2:00

6

@Frunsi no, because this problem stems from the fact that the destructor is trying to do something beyond the mere releasing of resources. It's tempting to say "i always want to end up doing XYZ" and thinking this is an argument for putting such logic in the destructor. No, don't be lazy, write xyz() and keep the destructor clean of non-RAII logic.
–
spraffAug 11 '12 at 21:11

Anything dangerous (i.e. that could throw an exception) should be done via public methods (not necessarily directly). The user of your class can then potentially handle these situations by using the public methods and catching any potential exceptions.

The destructor will then finish off the object by calling these methods (if the user did not do so explicitly), but any exceptions throw are caught and dropped (after attempting to fix the problem).

So in affect you pass the responsibility onto the user. If the user is in a position to correct exceptions they will manually call the appropriate functions and processes any errors. If the user of the object is not worried (as the object will be destroyed) then the destructor is left to take care of business.

An example:

std::fstream

The close() method can potentially throw an exception.
The destructs calls close() if the file has been opened but makes sure that any exceptions do not propagate out of the destructor.

So if the user of a file object wants to do special handling for problems associated to closing the file they will manually call close() and handle any exceptions. If on the other hand they do not care then the destructor will be left to handle the situation.

Scott Myers has an excellent article about the subject in his book "Effective C++"

"Unless you don't mind potentially terminating the application you should probably swallow the error." - this should probably be the exception (pardon the pun) rather than the rule - that is, to fail fast.
–
Erik ForbesSep 24 '08 at 22:05

8

I disagree. Terminating the program stops the stack unwind. No more destructor will be called. Any resources opened will be left open. I think swallowing the exception would be the prefered option.
–
Loki AstariSep 24 '08 at 22:15

9

The OS acan clean up resources it is the owner off. Memory, FileHandles etc. What about complex resources: DB connections. That uplink to the ISS you opened (is it automatically going to send the close connections)? I am sure NASA would want you to close the connection cleanly!
–
Loki AstariOct 3 '08 at 18:02

3

If an application is going to "fail fast" by aborting, it shouldn't be throwing exceptions in the first place. If it is going to fail by passing control back up the stack, it should not do so in a way that may cause the program to be aborted. One or the other, don't pick both.
–
TomDec 13 '08 at 22:06

Throwing out of a destructor can result in a crash, because this destructor might be called as part of "Stack unwinding".
Stack unwinding is a procedure which takes place when an exception is thrown.
In this procedure, all the objects that were pushed into the stack since the "try" and until the exception was thrown, will be terminated -> their destructors will be called.
And during this procedure, another exception throw is not allowed, because it's not possible to handle two exceptions at a time, thus, this will provoke a call to abort(), the program will crash and the control will return to the OS.

We have to differentiate here instead of blindly following general advice for specific cases.

Note that the following ignores the issue of containers of objects and what to do in the face of multiple d'tors of objects inside containers. (And it can be ignored partially, as some objects are just no good fit to put into a container.)

The whole problem becomes easier to think about when we split classes in two types. A class dtor can have two different responsibilities:

(R) release semantics (aka free that memory)

(C) commit semantics (aka flush file to disk)

If we view the question this way, then I think that it can be argued that (R) semantics should never cause an exception from a dtor as there is a) nothing we can do about it and b) many free-resource operations do not even provide for error checking, e.g. voidfree(void* p);.

Objects with (C) semantics, like a file object that needs to successfully flush it's data or a ("scope guarded") database connection that does a commit in the dtor are of a different kind: We can do something about the error (on the application level) and we really should not continue as if nothing happened.

If we follow the RAII route and allow for objects that have (C) semantics in their d'tors I think we then also have to allow for the odd case where such d'tors can throw. It follows that you should not put such objects into containers and it also follows that the program can still terminate() if a commit-dtor throws while another exception is active.

Highly agree. And adding one more semantic (Ro) rollback semantics. Used commonly in scope guard. Like the case in my project where I defined a ON_SCOPE_EXIT macro. The case about rollback semantics is that anything meaningful could happen here. So we really shouldn't ignore the failure.
–
pongbaAug 23 '13 at 6:55

The real question to ask yourself about throwing from a destructor is "What can the caller do with this?" Is there actually anything useful you can do with the exception, that would offset the dangers created by throwing from a destructor?

If I destroy a Foo object, and the Foo destructor tosses out an exception, what I can reasonably do with it? I can log it, or I can ignore it. That's all. I can't "fix" it, because the Foo object is already gone. Best case, I log the exception and continue as if nothing happened (or terminate the program). Is that really worth potentially causing undefined behavior by throwing from a destructor?

Its dangerous, but it also doesn't make sense from a readability/code understandability standpoint.

What you have to ask is in this situation

int foo()
{
Object o;
// As foo exits, o's destructor is called
}

What should catch the exception? Should the caller of foo? Or should foo handle it? Why should the caller of foo care about some object internal to foo? There might be a way the language defines this to make sense, but its going to be unreadable and difficult to understand.

More importantly, where does the memory for Object go? Where does the memory the object owned go? Is it still allocated (ostensibly because the destructor failed)? Consider also the object was in stack space, so its obviously gone regardless.

Then consider this case

class Object
{
Object2 obj2;
Object3* obj3;
virtual ~Object()
{
// What should happen when this fails? How would I actually destroy this?
delete obj3;
// obj 2 fails to destruct when it goes out of scope, now what!?!?
// should the exception propogate?
}
};

When the delete of obj3 fails, how do I actually delete in a way that is guaranteed to not fail? Its my memory dammit!

Now consider in the first code snippet Object goes away automatically because its on the stack while Object3 is on the heap. Since the pointer to Object3 is gone, you're kind of SOL. You have a memory leak.

Everyone else has explained why throwing destructors are terrible... what can you do about it? If you're doing an operation that may fail, create a separate public method that performs cleanup and can throw arbitrary exceptions. In most cases, users will ignore that. If users want to monitor the success/failure of the cleanup, they can simply call the explicit cleanup routine.

For example:

class TempFile {
public:
TempFile(); // throws if the file couldn't be created
~TempFile() throw(); // does nothing if close() was already called; never throws
void close(); // throws if the file couldn't be deleted (e.g. file is open by another process)
// the rest of the class omitted...
};

So destructors should generally catch exceptions and not let them propagate out of the destructor.

3 The process of calling destructors for automatic objects constructed on the path from a try block to a throw-
expression is called “stack unwinding.” [ Note: If a destructor called during stack unwinding exits with an
exception, std::terminate is called (15.5.1). So destructors should generally catch exceptions and not let
them propagate out of the destructor. — end note ]

Your destructor might be executing inside a chain of other destructors. Throwing an exception that is not caught by your immediate caller can leave multiple objects in an inconsistent state, thus causing even more problems then ignoring the error in the cleanup operation.

As an addition to the main answers, which are good, comprehensive and accurate, I would like to comment about the article you reference - the one that says "throwing exceptions in destructors is not so bad".

The article takes the line "what are the alternatives to throwing exceptions", and lists some problems with each of the alternatives. Having done so it concludes that because we can't find a problem-free alternative we should keep throwing exceptions.

The trouble is is that none of the problems it lists with the alternatives are anywhere near as bad as the exception behaviour, which, let's remember, is "undefined behaviour of your program". Some of the author's objections include "aesthetically ugly" and "encourage bad style". Now which would you rather have? A program with bad style, or one which exhibited undefined behaviour?

Q: So my question is this - if
throwing from a destructor results in
undefined behavior, how do you handle
errors that occur during a destructor?

A: There are several options:

Let the exceptions flow out of your destructor, regardless of what's going on elsewhere. And in doing so be aware (or even fearful) that std::terminate may follow.

Never let exception flow out of your destructor. May be write to a log, some big red bad text if you can.

my fave : If std::uncaught_exception returns false, let you exceptions flow out. If it returns true, then fall back to the logging approach.

But is it good to throw in d'tors?

I agree with most of the above that throwing is best avoided in destructor, where it can be. But sometimes you're best off accepting it can happen, and handle it well. I'd choose 3 above.

There are a few odd cases where its actually a great idea to throw from a destructor.
Like the "must check" error code. This is a value type which is returned from a function. If the caller reads/checks the contained error code, the returned value destructs silently.
But, if the returned error code has not been read by the time the return values goes out of scope, it will throw some exception, from its destructor.

I currently follow the policy (that so many are saying) that classes shouldn't actively throw exceptions from their destructors but should instead provide a public "close" method to perform the operation that could fail...

...but I do believe destructors for container-type classes, like a vector, should not mask exceptions thrown from classes they contain. In this case, I actually use a "free/close" method that calls itself recursively. Yes, I said recursively. There's a method to this madness. Exception propagation relies on there being a stack: If a single exception occurs, then both the remaining destructors will still run and the pending exception will propagate once the routine returns, which is great. If multiple exceptions occur, then (depending on the compiler) either that first exception will propagate or the program will terminate, which is okay. If so many exceptions occur that the recursion overflows the stack then something is seriously wrong, and someone's going to find out about it, which is also okay. Personally, I err on the side of errors blowing up rather than being hidden, secret, and insidious.

The point is that the container remains neutral, and it's up to the contained classes to decide whether they behave or misbehave with regard to throwing exceptions from their destructors.

Unlike constructors, where throwing exceptions can be a useful way to indicate that object creation succeeded, exceptions should not be thrown in destructors.

The problem occurs when an exception is thrown from a destructor during the stack unwinding process. If that happens, the compiler is put in a situation where it doesn’t know whether to continue the stack unwinding process or handle the new exception. The end result is that your program will be terminated immediately.

Consequently, the best course of action is just to abstain from using exceptions in destructors altogether. Write a message to a log file instead.