WEBVTT

00:01.700 --> 00:06.590
Hello again! In this video, we're going to look at declaration and initialization. So this is going

00:06.590 --> 00:12.170
to show the new features in C++ 11 concerned with declaring and initializing variables.

00:14.030 --> 00:19.640
We now have a universal initialization syntax. So you can initialize different types the same way.

00:21.360 --> 00:29.070
So, to do that, we put the initial value inside curly brackets, braces, so int x curly brackets seven is

00:29.070 --> 00:30.990
equivalent to int x equals seven.

00:31.560 --> 00:33.840
And by the way, you can still use the old ones if you like.

00:34.530 --> 00:36.690
It's a fairly tolerant language.

00:37.800 --> 00:39.240
You can also do this with strings.

00:39.240 --> 00:43.380
So instead of having rounded brackets, you can have curly brackets, which may not sound like a big

00:43.380 --> 00:43.680
deal.

00:44.770 --> 00:49.030
Something that is more of a big deal is that you can initialize containers with multiple values.

00:49.600 --> 00:55.300
So if we want to have a vector with elements four, two, three, five and one, we can just write one single

00:55.300 --> 01:01.960
statement which does that. As opposed to older versions where you have to declare the vector as an empty

01:01.960 --> 01:03.940
vector, then push back elements into it.

01:04.810 --> 01:08.350
Or alternatively, you could create the vector with five elements and then assign them all.

01:11.610 --> 01:18.420
Another useful feature is that it fixes a longstanding bug, arguably, that goes back to C. If you have

01:18.420 --> 01:22.050
a numeric type and you try to do some data that's too big for it.

01:22.470 --> 01:25.920
The extra data is just ignored and it'll be truncated.

01:26.280 --> 01:33.740
So in this case, you'd create an int with the value seven and the 0.7 bit is lost. And that is actually

01:33.750 --> 01:34.110
legal.

01:34.500 --> 01:37.050
Although with modern compilers, you may well get a warning.

01:37.960 --> 01:42.520
If you use the modern syntax with curly brackets, then that's not actually allowed.

01:42.550 --> 01:46.840
You'll get a compiler error. And then you'll realize there's a mistake in the code and you need to fix it.

01:49.120 --> 01:51.640
Also, this syntax is much more consistent.

01:54.620 --> 01:58.910
The vector constructor with one argument, creates a vector with that many elements which are value

01:58.910 --> 01:59.480
initialized.

01:59.960 --> 02:02.450
So in this case, we'd have four elements with value zero.

02:03.410 --> 02:07.330
If you have two arguments, then it's the number of arguments and the initial value.

02:07.340 --> 02:12.050
So we'd have four elements with value two. With the new form,

02:13.070 --> 02:14.510
you get exactly what you ask for.

02:14.540 --> 02:20.090
So in this case, we have one element with value four, and we have two elements with value four and two.

02:22.190 --> 02:27.680
And finally, it's also fixes another longstanding C++ annoyance, or maybe it's a fairly small one!

02:29.360 --> 02:31.850
So what exactly does this code do?

02:32.390 --> 02:37.100
You may think that you're creating an object of class Test by calling the default constructor.

02:38.270 --> 02:42.970
In fact, the compiler will think that you're declaring a function which returns an object of class

02:42.980 --> 02:43.430
Test.

02:45.010 --> 02:51.700
And that's known as "the most vexing parse." If you use the new syntax with curly braces, if you have

02:51.700 --> 02:55.960
nothing inside the braces, that indicates no arguments or the default constructor.

02:56.420 --> 02:58.900
And in that case, you are creating an object.

03:02.890 --> 03:08.170
So here is the code. I have written a function to print out the vector elements. That's going to save

03:08.170 --> 03:10.450
as a bit of time in the next example.

03:13.060 --> 03:19.540
This takes the victor by reference to const. As we saw in the video earlier, the last video or the

03:19.540 --> 03:24.880
one before, maybe, this is the best way to pass an object if you just want to look at its data.

03:26.670 --> 03:30.090
And then we iterate over all the elements in the vector and print them out.

03:30.360 --> 03:35.190
If you haven't seen this syntax before, don't worry, I'm going to go over it a little bit later in the course.

03:36.090 --> 03:37.630
It's just a simple way of writing out

03:37.770 --> 03:38.400
iterators.

03:38.880 --> 03:41.310
And if you don't know what iterators are, I'm going to cover those as well!

03:45.010 --> 03:46.570
Okay, so let's try this code out.

03:48.850 --> 03:53.560
So there we are, we get x equals seven, string is "let us begin" and the vector elements are four, two,

03:53.560 --> 03:54.520
three, five and one.

03:55.540 --> 03:55.920
OK.

04:01.390 --> 04:05.770
So here's some code with the narrowing conversion. We're going to try it, first of all, with the old

04:05.770 --> 04:10.270
syntax. So we are going truncate this value of 7.7 down to seven.

04:11.200 --> 04:12.310
So let's see what happens.

04:15.040 --> 04:17.230
So it compiles and runs, and we get y equals seven.

04:17.650 --> 04:22.990
And we also get a compiler warning saying that "conversion from double to int: possible loss

04:22.990 --> 04:23.770
of data."

04:25.180 --> 04:25.530
OK.

04:27.910 --> 04:34.360
And then if we try it with the new syntax, so we comment that one out and we use this one with the curly

04:34.360 --> 04:34.870
brackets.

04:37.640 --> 04:42.680
All right, we actually get an error. "Conversion from table to which requires a loving conversion."

04:45.770 --> 04:50.190
So the compiler doesn't take that. So let's comment this bit out, to avoid confusing things.

04:52.040 --> 04:53.990
And here are the vector definitions.

04:53.990 --> 04:55.130
So let's just check those.

04:57.350 --> 05:04.520
So we get that one gives zero, zero, zero, zero, that one gives 2, 2, 2, 2. That one gives one [element with value four] and that

05:04.520 --> 05:05.900
one gives four and two.

05:10.080 --> 05:17.970
And then finally, the Test declaration. I've written an empty Test class up here just to make this

05:17.970 --> 05:23.550
compile. And the print function and the includes are the same as they were before.

05:28.940 --> 05:35.900
So there's no problem without that. If I uncomment this, we expect that we'll get a compiler error

05:35.900 --> 05:39.740
because we're defining this symbol test with a lowercase 't' twice.

05:41.940 --> 05:46.860
What we might not expect is that we get an error saying that the previous definition was a function.

05:47.430 --> 05:51.630
So this is actually interpreted as a function definition and this one isn't.

05:52.350 --> 05:57.150
So that demonstrates the difference between the two forms of defining the variable.

06:01.860 --> 06:05.460
Another small but important change, or a useful change anyway.

06:05.820 --> 06:13.230
If you have a template whose parameter type is also a template, you no longer have to put a space between

06:13.230 --> 06:14.130
the two arrows.

06:14.550 --> 06:18.720
If you're using older versions of C++, you have to put a space in there.

06:19.080 --> 06:23.400
Otherwise, the compiler got confused and thought you were trying to do a right shift or do some input

06:23.400 --> 06:24.240
or something like that.

06:25.350 --> 06:28.590
But now the compiler can actually understand it's a nested template.

06:30.240 --> 06:31.980
So let's just check that compiles.

06:32.380 --> 06:33.630
Yep, there we go, no problem.

06:35.760 --> 06:39.300
Of course, if you write code like this, it's going to get pretty unpleasant.

06:39.300 --> 06:43.380
You have lots of angle brackets flying around all over the place, and it gets pretty hard to read.

06:44.340 --> 06:48.850
So the best way to handle that is to write an alias or create an alias for vector of ints

06:48.900 --> 06:58.290
in this case. In older versions of C++, you'd use a typedef. So you put typedef and then the vector

06:58.290 --> 07:01.060
of int, and then we put the alias.

07:01.080 --> 07:07.740
So whenever we put "IntVec", the compiler will replace this by vector of int. And then we can define

07:07.740 --> 07:09.350
a vector of IntVec.

07:13.150 --> 07:16.960
C++ now has a nicer syntax for doing that, or at least I think it's nicer.

07:17.590 --> 07:25.750
So you put using, and then IntVec, and then equals and then we have the vector of int.

07:25.760 --> 07:29.200
The advantage of this is if you have a lot of these definitions and you're scrolling down trying to find one.

07:29.410 --> 07:34.510
It's much easier to look for something on the left hand side of an equal sign than it is for something

07:34.510 --> 07:35.800
at the right of an expression.

07:37.350 --> 07:40.890
At least if you're used to using an alphabet that goes from left to right.

07:41.280 --> 07:46.890
If your native alphabet goes from right to left, you may not see the problem. But you can either.

07:47.250 --> 07:47.970
Each to their own!

07:49.730 --> 07:51.170
So let's check that again.

07:51.200 --> 07:52.370
Okay, that does compile.

07:55.930 --> 07:58.710
And then finally, the famous null pointer.

08:00.490 --> 08:08.080
So C and C++ defined a macro NULL, in capitals, which has the value zero. But the  the language doesn't

08:08.080 --> 08:09.580
actually say what the type of NULL is!

08:10.210 --> 08:13.000
So some compilers use int and some use pointer to int.

08:13.840 --> 08:16.090
And some use something else altogether.

08:18.970 --> 08:22.480
In C++ 11, we now have a special type for the NULL pointer.

08:24.010 --> 08:28.750
It can be converted to any other kind of pointer, but it can't be converted to an integer.

08:29.860 --> 08:34.870
And this has actually uncovers quite a lot of bugs in which people were using the null pointer to represent

08:34.870 --> 08:35.480
the number zero.

08:39.690 --> 08:43.260
So here's a little program to try this out (I'm going up in the world again!)

08:46.670 --> 08:52.530
So we have two functions, one of which takes an int and the other one takes a pointer to int.

08:53.660 --> 08:56.360
And we're going to call them with NULL and nullptr as argument.

08:57.230 --> 09:00.320
So if NULL is implemented as an int, it's going to call this one.

09:01.430 --> 09:05.360
If it's implemented as a pointer to int, it's going to call this one.

09:06.170 --> 09:09.410
And if it's implemented as something else, then it might not work at all!

09:11.860 --> 09:16.870
nullprt is defined as being convertible to any kind of pointer, but not to an integer.

09:17.560 --> 09:18.880
So it should call this one.

09:19.330 --> 09:20.350
So let's see what happens.

09:26.490 --> 09:27.330
(Get the focus on the... !)

09:29.690 --> 09:34.850
So the function which takes an int gets called, so NULL is an int, and then the function which takes

09:34.850 --> 09:37.430
a pointer is called so, null pointer is...

09:38.870 --> 09:40.630
Well, it's compatible with pointer to int anyway.

09:42.280 --> 09:47.050
If we'd done this with clang, then they'd both call the function which takes a pointer because clang

09:47.080 --> 09:49.280
implements NULL as points to int.

09:50.050 --> 09:55.120
And if we'd done it with GNU's compiler g++, then we'd have got a compiler error because

09:55.600 --> 10:00.580
NULL is implemented as something else and neither of these functions actually matches.

10:01.550 --> 10:03.250
Okay, so that's it for this video.

10:03.490 --> 10:08.170
As darkness descends upon my recording studio, such as it is!

10:09.130 --> 10:10.360
I'll see you in the next video.

10:10.360 --> 10:12.460
But meanwhile, keep coding.
