WEBVTT

00:00.180 --> 00:03.870
Hello again! In this video, we are going to look at the noexcept keyword.

00:04.800 --> 00:06.750
This came in, in C++11.

00:07.110 --> 00:10.420
It replaces the older throw() with an empty exception list.

00:11.190 --> 00:16.680
We can declare a function as noexcept and that means that the function does not throw exceptions.

00:17.160 --> 00:18.570
Or at least it is not supposed to.

00:19.320 --> 00:23.820
So this is the new version of writing throw() with an empty exception list.

00:24.870 --> 00:28.380
If an exception is thrown, then the program terminates immediately.

00:30.750 --> 00:36.030
Noexcept is a promise to callers of this function that it is not going to throw any exceptions.

00:36.660 --> 00:40.500
So a noexcept function provides the "no throw" guarantee.

00:41.130 --> 00:46.350
And that is helpful to us if we are writing exception-safe codes and we want to call that function.

00:47.340 --> 00:49.710
noexcept also has performance advantages.

00:50.130 --> 00:53.040
It helps the compiler generate better-optimized code.

00:53.820 --> 00:58.410
It gives the compiler more information about what the code might or might not do.

00:59.100 --> 01:02.460
So the compiler might be able to make some extra assumptions, which save time.

01:03.390 --> 01:07.620
And it also means that the compiler does not neede to generate code for stack unwinding for that

01:07.620 --> 01:08.100
function.

01:10.310 --> 01:16.640
In modern C++, we have optimized versions of some operators, which are not necessarily exception-safe.

01:17.570 --> 01:19.850
We will talk about this when we cover move semantics.

01:20.930 --> 01:26.690
The standard library will only use these operators if they are declared noexcept. Otherwise it is going

01:26.690 --> 01:31.550
to be cautious and call the older versions, which are not optimized but safer.

01:32.090 --> 01:38.030
So if you do not declare things as noexcept, you may lose out on these optimized operators.

01:40.370 --> 01:41.540
So when should we use

01:41.630 --> 01:42.260
noexcept?

01:42.680 --> 01:47.810
And the answer is, wherever possible. If we are certain that a function is not going to throw any

01:47.810 --> 01:54.230
exceptions, or not call functions, which might have exceptions. It is also useful if we could get

01:54.230 --> 01:56.810
an exception, but there is nothing useful we could do.

01:57.710 --> 02:01.190
And the safest thing to do is to shut down the program, before anything else goes wrong.

02:01.490 --> 02:04.160
So that is another situation where noexcept is useful.

02:05.300 --> 02:12.950
So, some examples where we could use noexcept are: overloading the standard swap() function, and for class destructors.

02:16.510 --> 02:21.930
We cannot overload on being noexcept: a function can only be one or the other.

02:21.960 --> 02:23.320
You cannot have two different versions.

02:24.190 --> 02:28.930
noexcept is part of the function's type, but it is not part of the function's signature.

02:29.320 --> 02:32.230
So that is similar reasoning to the return type.

02:32.410 --> 02:35.080
You cannot overdo it on return value in C++, either.

02:39.800 --> 02:44.210
With class hierarchies, the property of being noexcept is inherited.

02:44.780 --> 02:51.470
So if you have a virtual function in the base class, which is noexcept, then all the overrides in derived

02:51.470 --> 02:53.360
classes must also be noexcept.

02:54.740 --> 03:00.080
If you have inheriting constructors, these will be noexcept if the basic class constructor is no

03:00.080 --> 03:00.530
accept.

03:01.280 --> 03:06.680
And if we let the compiler synthesize special member functions for us, these will automatically be

03:06.680 --> 03:10.010
noexcept, if the version in the base class is noexcept.

03:12.400 --> 03:19.030
We can also make a child member function more exception safe than the parent's, but not the other way

03:19.030 --> 03:19.260
round.

03:20.080 --> 03:26.440
If we have a virtual function in the base case, which can throw, we can write an override in the child class, which

03:26.440 --> 03:27.130
is noexcept.

03:27.640 --> 03:28.780
But you cannot go the other way.

03:29.020 --> 03:35.230
You cannot have a noexcept function in the base class and then have a child override which throws exceptions.

03:35.590 --> 03:36.590
So that is similar to const.

03:36.670 --> 03:41.290
You can make the child version more const, but you cannot make it less than the parent's.

03:42.750 --> 03:49.800
And finally, if you do not make destructors noexcept, the compiler might do that for you anyway.

03:50.220 --> 03:56.070
This can happen if all the members of your class have a noexcept destructor, or they are built-in types,

03:57.030 --> 04:02.040
and all the parent classes of your class have a noexcept destructor. In that case,

04:02.040 --> 04:05.130
the compiler will also assume that your destructor is noexcept.

04:06.210 --> 04:13.410
So if you have existing code from before C++ 11, which does not use noexcept, then you just have

04:13.410 --> 04:16.920
to recompile this, and the destructors will now be noexcept.

04:17.340 --> 04:20.610
So you get the benefit of that, without having to modify your code.

04:22.050 --> 04:26.430
If you are writing new code, though, it is better to write noexcept. It is always better to make things

04:26.430 --> 04:27.420
explicit if you can.

04:28.230 --> 04:29.670
Okay, so that is it for this video.

04:30.150 --> 04:33.300
I will see you next time, but until then, keep coding!
