So imagine you'v开发者_开发问答e got an exception you're catching and then in the catch you write to a log file that some exception occurred. Then you want your program to continue, so you have to make sure that certain invariants are still in a a good state. However what actually occurs in the system after the exception was "handled" by a catch?
The stack has been unwound at that point so how does it get to restore it's state?
"Stack unwinding" means that all scopes between throw
and the matching catch
clause are left, calling destructors for all automatic objects in those scopes, pretty much in the same way function scopes are left when you return from a function.
Nothing else "special" is done, the scope of a catch
clause is a normal scope, and leaving it is no different from leaving the scope of an else
clause.
If you need to make sure certain invariants still hold, you need to program the code changing them in a thread-safe manner. Dave Abrahams wrote a classic on the different levels of exception safety, you might want to read that. Basically, you will have to consequently employ RAII in order to be on the safe side when exceptions are thrown.
Only objects created inside the try
will have been destroyed during unwinding. It's up to you to write a program in such way that if an exception occurs program state stays consistent - that's called exception safety.
C++ doesn't care - it unwinds stack, then passes control into an appropriate catch
, then control flow continues normally.
It is up to you to ensure that the application is recovered into a stable state after catching the exception. Usually it is achieved by "forgetting" whatever operation or change(s) produced the exception, and starting afresh on a higher level.
This includes ensuring that any resources allocated during the chain of events leading to the exception gets properly released. In C++, the standard idiom to ensure this is RAII.
Update
For example, if an error occurs while processing a request in a web server, it generates an exception in some lower level function, which gets caught in a higher level class (possibly right in the top level request handler). Usually the best possible thing to do is to roll back any changes done and free any resources allocated so far related to the actual request, and return an appropriate error message to the client. Changes may include DB transactions, file writes, etc - one must implement all these in an exception safe manner. Databases typically have built in transactions to deal with this; with other resources it may be more tricky.
This is up to the application. There are several levels of exception-safety. The level you describe is hard to achieve for the whole application.
Certain pieces of code, however, can be made 'Failure transparent', by using techniques like RAII, and by smartly ordering the sequence of actions. I could imagine a piece of code querying several urls for data, for instance: when one url would 'throw', the rest of the urls can still be handled. Or it can be retried...
If you have exception handling in every function you can resume on the next higher level but its rather complicated, in fact I use exceptions mainly to detect errors as close to the source as possible but don't use them for resuming execution.
if on the other hand there are errors that are predictable one can devise schemes to handle that, but for me exceptions are considered exceptions so I tend to try and exit gracefully instead with a good hint in the log file where it happened. JM2CW
It can't. Exceptions aren't resumable in C++. Nor in most modern languages; some of the first languages to support exceptions did support resumable exceptions, and found that it wasn't a good idea.
If you want to be able to resume from some specific point, you have to put your try/catch block there. If you just want to log and continue, don't throw the exception in the first place.
精彩评论