Hello again! In this video, we are going to look at the exception mechanism. So what actually happens
when an exception is thrown?
And we are also going to find out how to re-throw an exception.
When an exception is thrown, several things happen.
First of all, the exception object, which is being thrown, that gets copied into a special area of
memory, which is not part of the local stack.
This area in memory is set up by the compiler and any catch block which can handle that exception type
is able to access that memory.
So that is how the exception object gets transferred from one part of the program to the other.
Every local variable in this scope is destroyed, which includes the original copy of the thrown object.
And the program will immediately leave this scope, without executing any further instructions.
So this is rather like having a return statement in a function call.
The program is then going to look for a catch block, to handle the exception. If the exception is thrown
in a try block, it is going to look in the catch blocks which follow after that try block.
If it cannot find one, it is going to destroy all the local variables and exit this current scope.
So if you imagine the call stack, we have this stack of function calls. And the program's exception
handling mechanism is going to go up this stack, looking for a suitable handler, and cleaning the stack
up as it goes.
If it gets all the way to main() without finding one, then the program is terminated.
And this process of repeatedly destroying local variables and exiting the current scope, is known as a
"stack unwinding".
When the program finds a suitable handler for the exception, it will execute the code in that catch
block, and then it will continue. So normally it will go on to the next instruction after the catch block.
So that is a bit like returning from a function.
It will execute the next instruction after the function call.
It is possible for the handler to re-throw the exception.
So that means that this exception becomes "live" again, it becomes active. And then the program needs
to finds another handler for it.
To do that, we use the "throw" key word.
If we just put throw, followed by a semi-colon, that is going to throw the original object again.
If we put throw followed by an object, then it is going to throw a copy of that object.
And this can only happen in a catch block.
So it is going to be regarded as a completely new exception.
And then the stack unwind begins again.
So let's have a look at an example.
We have our vector access, inside to try block, in this function.
We have a handler for the out_of_range exception.
So this is going to produce some output. And then we are going to re-throw this exception.
So the program is now going to look for a handler in the enclosing scope.
But there are no more handlers in this function.
So it is going to return to the caller, and look for a catch block there, and it is going to find this one.
So when we run this program, we expect to see the output from this catch handler, followed by the
output from the catch handler in main() for the generic exception.
And that is what we get.
So there is the output from this handler, and there is the output from the generic exception handler.
If we throw some other type of object, so let's say we have a generic exception, which is based on
this out_of_range exception.
So let's see what happens.
So we have the output from the catch block in func() again, and we have the main() catch block again.
And because we caught by reference in main(), polymorphism works. We get the right virtual member function.
So this will call the version of what for the out_of_range exception, and not the generic version.
So why would this be useful?
One situation is where you have an exception that you want to handle somewhere else, but you want
to log the information about the error condition where it happens, when you still have all the
information.
You could also add extra information to the exception.
And also, you can convert the exception to a higher level type, like we did by converting the out_of_range
exception to a generic exception.
So here is a code fragment, which does that. We have a low level networking exception, with lots of complicated
technical details.
We can log all these details. We have some sort of logging stream, we do not really need to worry
about that here, and then we can write the details to the log file.
We have a member in this class that we can use, to say which server we are trying to connect to.
So we can populate that. And then we can re-throw the exception with all this information, after we have
logged all the data.
Or we could convert it to a higher level exception.
OK, so that is it for this video.
I will see you next time, but until then, keep coding!