Why destructor cannot throw exception




















Since the pointer to Object3 is gone, you're kind of SOL. You have a memory leak. Also see this FAQ. So destructors should generally catch exceptions and not let them propagate out of the destructor.

I am in the group that considers that the "scoped guard" pattern throwing in the destructor is useful in many situations - particularly for unit tests. Even if you add no specification and define your destructor like this:. The compiler will still invisibly add specification noexcept to your destructor. And this means that the moment your destructor throws an exception, std::terminate will be called, even if there was no double-exception situation.

If you are really determined to allow your destructors to throw, you will have to specify this explicitly; you have three options:. Finally, if you do decide to throw in the destructor, you should always be aware of the risk of a double-exception throwing while the stack is being unwind because of an exception. This would cause a call to std::terminate and it is rarely what you want. 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.

Everyone else has explained why throwing destructors are terrible 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. 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? The main problem is this: you can't fail to fail. What does it mean to fail to fail, after all?

If committing a transaction to a database fails, and it fails to fail fails to rollback , what happens to the integrity of our data?

Since destructors are invoked for both normal and exceptional fail paths, they themselves cannot fail or else we're "failing to fail". This is a conceptually difficult problem but often the solution is to just find a way to make sure that failing cannot fail. For example, a database might write changes prior to committing to an external data structure or file. The pragmatic solution is perhaps just make sure that the chances of failing on failure are astronomically improbable, since making things impossible to fail to fail can be almost impossible in some cases.

The most proper solution to me is to write your non-cleanup logic in a way such that the cleanup logic can't fail. For example, if you're tempted to create a new data structure in order to clean up an existing data structure, then perhaps you might seek to create that auxiliary structure in advance so that we no longer have to create it inside a destructor.

This is all much easier said than done, admittedly, but it's the only really proper way I see to go about it. Sometimes I think there should be an ability to write separate destructor logic for normal execution paths away from exceptional ones, since sometimes destructors feel a little bit like they have double the responsibilities by trying to handle both an example is scope guards which require explicit dismissal; they wouldn't require this if they could differentiate exceptional destruction paths from non-exceptional ones.

Still the ultimate problem is that we can't fail to fail, and it's a hard conceptual design problem to solve perfectly in all cases. It does get easier if you don't get too wrapped up in complex control structures with tons of teeny objects interacting with each other, and instead model your designs in a slightly bulkier fashion example: particle system with a destructor to destroy the entire particle system, not a separate non-trivial destructor per particle. And that's one of the easiest solutions naturally is to use destructors less often.

In that case, instead of invoking such logic through the particle's dtor which could be executed in an exceptional path, you could instead have it all done by the particle system when it removes a particle.

Removing a particle might always be done during a non-exceptional path. If the system is destroyed, maybe it can just purge all particles and not bother with that individual particle removal logic which can fail, while the logic that can fail is only executed during the particle system's normal execution when it's removing one or more particles.

There are often solutions like that which crop up if you avoid dealing with lots of teeny objects with non-trivial destructors. Where you can get tangled up in a mess where it seems almost impossible to be exception-safety is when you do get tangled up in lots of teeny objects that all have non-trivial dtors. This way we'd be able to catch all this stuff at compile-time if we actually write a destructor inadvertently which could throw.

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? 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.

If it returns true, then fall back to the logging approach. 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. 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.

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. 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. 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 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.

Set an alarm event. Typically alarm events are better form of notifying failure while cleaning up objects.

You should eat any errors. You're freeing memory, closing connections, etc. Nobody else in the system should ever SEE those things again, and you're handing back resources to the OS. If it looks like you need real error handling here, its likely a consequence of design flaws in your object model. This also lets you implement policy and different error handling just by building a different wrapper e. The problem of throwing exceptions out a destructor is that destructors of successfully created objects which scopes are leaving while handling an uncaught exception it is after an exception object is created and until completion of a handler of the exception activation , are called by exception handling mechanism; and, If such additional exception from the destructor called while processing the uncaught exception interrupts handling the uncaught exception, it will cause calling std::terminate the other case when std::exception is called is that an exception is not handled by any handler but this is as for any other function, regardless of whether or not it was a destructor.

If handling an uncaught exception in progress, your code never knows whether the additional exception will be caught or will archive an uncaught exception handling mechanism, so never know definitely whether it is safe to throw or not. But in practice such separating into two possible behaviours is not useful - it just does not help you to make a well-designed program. If you throw out of destructors ignoring whether or not an uncaught exception handling is in progress, in order to avoid possible calling std::terminate , you must guarantee that all exceptions thrown during lifetime of an object that may throw an exception from their destructor are caught before beginning of destruction of the object.

It is quite limited usage; you hardly can use all classes which would be reasonably allowed to throw out of their destructor in this way; and a combination of allowing such exceptions only for some classes with such restricted usage of these classes impede making a well-designed program, too. Stack Overflow for Teams — Collaborate and share knowledge with a private group.

Create a free Team What is Teams? Collectives on Stack Overflow. Learn more. If a function is declared as nothrow throws an exception anyway, that is a bug pure and simple. Just mark it noexcept.

Sign up to join this community. The best answers are voted up and rise to the top. Stack Overflow for Teams — Collaborate and share knowledge with a private group. Create a free Team What is Teams? Learn more. How to make sure that the destructor cannot throw an exception?

Ask Question. Asked 6 years, 8 months ago. Active 5 years, 10 months ago. Viewed 2k times. Improve this question. Ayush Chaurasia Ayush Chaurasia 31 4 4 bronze badges. All I can say is code it properly. Bang you're dead. The easy way to prevent this is never throw an exception from a destructor. But if you really want to be clever, you can say never throw an exception from a destructor while processing another exception. But in this second case, you're in a difficult situation: the destructor itself needs code to handle both throwing an exception and doing "something else", and the caller has no guarantees as to what might happen when the destructor detects an error it might throw an exception, it might do "something else".

So the whole solution is harder to write. So the easy thing to do is always do "something else". That is, never throw an exception from a destructor. Of course the word never should be "in quotes" since there is always some situation somewhere where the rule won't hold.

Click here for a personal note from Marshall Cline.



0コメント

  • 1000 / 1000