Hello again! In this video, we are going to start looking at exceptions in C++.
We are going to start off by looking at an example of an exception which is thrown by the standard library.
This does not actually happen as often as you might expect.
The reason is that the standard library has to work with every environment, including ones which do
not support exceptions.
So when it does throws exceptions, it is usually in something where you can avoid it.
As an example, if we have a vector and we use subscript access.
This will not perform any range checking.
The idea is that you should know if the elements is in the vector or not.
So there is no point wasting time checking. If you do access an element which is out of bounds,
Then there is no warning, no error condition.
The program will carry on, and probably crash or behave strangely.
I'm actually going to use GNU C++ for my examples in this video, because the output is more useful for
my purposes.
So there we are.
Segmentation fault, which is Unix's way of saying the program crashed.
There is also a member function called at(), which does perform range checking. This will check its arguments
at run time.
And if that is not a valid index, it is going to create an exception object.
As you can see, we are not actually doing anything to handle this exception object.
So, what do you think will happen?
And the answer is, the program should terminate.
So let's see what happens.
OK, so the program does terminate.
It has called the library's terminate() function, which does what its name says. It has thrown an instance,
or an object, of "out_of_range".
So what is that?
And there is also some output, which we will come back to in a minute.
In C++, you are actually allowed to use any type you want for an exception object, including built-in
types and your own types. That got rather confusing.
So in C++ 98, they provided a standard exception class for the language.
This gives a consistent interface for exception objects.
It is actually the base class of an inheritance hierarchy.
So this is one of the very few examples of where the library uses inheritance polymorphism.
This exception class has a number of subclasses, which includes the "out_of_range" that we just saw.
It also has a virtual member function, called what().
And this will return a string, a C-style string, which describes the error condition.
So if we go back to our output, it actually called what().
And the string is a bit..
jargonish, but you can see there is a range check of something which is two, and the size is zero.
So that is why things went wrong.
Let's try now to rewrite our example, so the exception is handled and the program will continue gracefully,
instead of being terminated. The compiler will actually do most of the work for us, but we need to tell
the compiler that we want the extra code.
To do this, we take the code, which is likely to have a run-time error, and we put that inside its
own block again, and we put the "try" key word in front of this block.
So this will make the compiler
generate the necessary code.
Then for the handler, we have another block with the catch key word in front of it. After the catch
key word, we put some round brackets with the type of the exception.
So this is a bit like a function argument, although not exactly the same.
If we put the base class in here, the exception, this will handle any subclass
of that exception class. If we catch it by reference, then dynamic bining will be used.
And if we call the what() member function, we will get the correct version for the subclass.
So let's try that out.
We have our vector again.
We have our access inside of the try block.
And then we have the exception handler, which follows straight after the try block.
So we are going to catch the exception, and its subclasses, by reference.
And in our handler, we are just going print out that we have an exception and then call the what() member
function.
So there we are. We get the "exception caught", and then we get the string returned by what().
If we catch it by value, what do you think will happen?
If we catch it by value, then static binding is going to be used.
So the result of calling what() will be to call the exception class version.
And there we are. So, "exception caught". And the exception version of what() just says this is an exception.
So normally, you put the catch block straight after the try block, to catch the exceptions which are
thrown in there.
What happens if the catch block does not handle that particular exception.
In that case, the program will jump out of the enclosing scope.
So if we are in a function, it is going to return to the caller.
Then it is going to look in the caller for a suitable catch handler, and if there is no suitable, it
is going to go to the caller's, caller, and so on.
Eventually, it will get to the main function and there is nothing to do.
So the program will terminate.
Okay, so that is it for this video.
I will see you next time.
But until then, keep coding!