WEBVTT

00:00.120 --> 00:04.620
Hello again! In this video, we are going to start looking at the standard exception hierarchy.

00:05.680 --> 00:12.730
C++ has a standard exception class in the library, and this is the base of an inheritance hierarchy.

00:13.270 --> 00:19.450
So if we use this hierarchy for our exceptions, we will have a consistent interface for all exception

00:19.450 --> 00:19.930
objects.

00:20.410 --> 00:25.750
And also, we can take advantage of polymorphism. So we can just write one handler, which takes the

00:25.750 --> 00:28.120
exception base class by reference.

00:28.690 --> 00:35.620
We only need to write separate handlers for subclasses if we want to do something different for a specific

00:35.620 --> 00:36.280
subclass.

00:40.050 --> 00:43.350
The hierarchy looks like this. We have the exception as the base.

00:43.860 --> 00:49.290
Then we have these classes, which we are going to look at in the next video. We can recognize bad_alloc,

00:49.290 --> 00:51.450
which is for memory allocation errors.

00:52.020 --> 00:56.760
And there is also bad_cast, which we will cover when we look at run-time type information.

00:57.600 --> 00:59.700
So these are leaf classes of the exception.

01:00.180 --> 01:05.460
There are also two sub-hierarchies, runtime_error and so-called logic_error.

01:06.030 --> 01:08.730
And we can see that out_of_range is a logic_error.

01:13.510 --> 01:18.850
The idea of these classifications is that a logic error is something that the programmer could have

01:18.850 --> 01:24.370
prevented, whereas a runtime error is something that the programmer cannot do anything about.

01:25.240 --> 01:28.050
Typically, logic errors involve preconditions.

01:28.060 --> 01:33.190
For example, if a function must never be called with argument 0, then the programmer can check

01:33.190 --> 01:34.690
for that before calling the function.

01:35.620 --> 01:40.960
On the other hand, if some program on the computer goes crazy and uses up all the memory, then there is

01:40.960 --> 01:42.490
nothing you can do about that.

01:45.050 --> 01:48.440
The exception base class defines five public member functions.

01:48.770 --> 01:50.720
So that is the interface of the hierarchy.

01:51.260 --> 01:55.970
We have the usual special member functions: constructor, copy constructor, assignment operator.

01:56.690 --> 02:02.360
There is a virtual member function called what(), and that means that the destructor has to be virtual

02:02.360 --> 02:02.780
as well.

02:03.200 --> 02:08.810
And I hope you remember why that is: it is to make sure that all the destructors are called when a child

02:09.140 --> 02:10.820
is destroyed through a reference to the base.

02:12.410 --> 02:17.480
This what() function will return a C string, and it cannot throw exceptions.

02:17.840 --> 02:19.310
And we certainly do not want it to!

02:22.700 --> 02:28.310
The exception class and its leaf children, bad_alloc and bad_cast, have default constructors.

02:29.390 --> 02:31.790
The others do not have a default constructor.

02:32.180 --> 02:37.940
Instead, they have a constructor which takes a single string argument, and that can be either a C string

02:38.300 --> 02:40.190
or a C++ library string.

02:41.290 --> 02:47.770
When the what() member function is called, this string is returned, so it is important that this constructor

02:47.770 --> 02:50.530
arguments gives information about the error condition.

02:54.330 --> 02:59.610
We saw that we can do bounds checking with vectors, by calling the at() member function, and we can actually

02:59.610 --> 03:00.720
implement that ourselves.

03:01.590 --> 03:07.560
Obviously, we cannot change the library vector, but we can write a non-member function which takes a vector

03:07.560 --> 03:08.550
and does the same thing.

03:09.420 --> 03:12.240
So this needs to take the vector and also the index.

03:12.960 --> 03:15.630
The return type will be the same as the element type.

03:16.260 --> 03:18.030
I am just using a vector of int here, but

03:18.270 --> 03:21.540
you can be generic and write a template function if you like.

03:23.010 --> 03:25.940
We need to check that the index is valid.

03:27.450 --> 03:31.410
If the index is not valid, then we need to throw the out_of_range exception.

03:31.830 --> 03:37.770
So we create an out_of_range object by calling the constructor, and we pass a string as argument.

03:38.550 --> 03:44.580
So we have a local variable, which contains some information about the error condition, and we pass that

03:44.580 --> 03:47.730
as argument. And then we throw the exception.

03:48.480 --> 03:52.350
So the program will call the destructor for this local string variable.

03:52.980 --> 03:54.540
Then it will jump out of the if block.

03:54.900 --> 03:56.940
It will look for a handler in the enclosing scope.

03:57.660 --> 04:01.230
There is nothing in this at() function, so it is going to go to the caller.

04:02.530 --> 04:08.290
In main(), we are calling this inside a try block, which has a handler for any child of exception.

04:08.800 --> 04:14.350
So this exception will be caught and handled in main(). And that is the exceptional program flow.

04:17.190 --> 04:22.860
If the index is valid, then we can just carry on and use the subscript to get the element value

04:22.860 --> 04:23.700
and return it.

04:25.310 --> 04:31.130
So let's try this. We have a vector with three elements, so we should be able to access the element

04:31.130 --> 04:36.110
with index 2 and get the value of that element, which is 3.

04:36.710 --> 04:37.280
And there we are.

04:41.550 --> 04:45.970
If we try this with an empty vector, then what should happen?

04:46.950 --> 04:51.240
This condition is going to be false, and we are going to throw an exception, which should be caused by

04:51.240 --> 04:52.380
this handler in main().

04:53.100 --> 04:54.240
So let's see if that works.

04:56.540 --> 04:59.210
And yes, it does. So exception is caught in main().

04:59.690 --> 05:01.400
And that is the what() string.

05:01.790 --> 05:08.480
So when we constructed the object, the argument that we gave is the message that we get when we call

05:08.480 --> 05:08.780
what().

05:11.110 --> 05:15.430
And finally, C++11 added a few new classes to the hierarchy.

05:16.150 --> 05:19.660
So bad_alloc now has a child, which is bad_array_new_length.

05:20.320 --> 05:27.100
So if you are calling new to allocate an array and the number of elements is invalid, then this will

05:27.100 --> 05:27.540
be thrown.

05:28.570 --> 05:34.420
There are a few new exceptions for C++11 features we have not yet covered: weak pointer, standard

05:34.420 --> 05:36.460
function and standard future.

05:37.680 --> 05:40.140
And I am sorry, but this does not involve time travel.

05:40.560 --> 05:41.620
It is about multi-threading.

05:43.110 --> 05:50.070
There's also a new sub-hierarchy, system_error, underneath runtime_error, and this has one child, ios_base_failure.

05:50.070 --> 05:53.610
So we can now get streams to throw exceptions.

05:54.630 --> 05:56.070
Okay, so that is it for this video.

05:56.460 --> 05:57.350
I will see you next time.

05:57.600 --> 05:59.580
Until then, keep coding!
