Hello again! In this video, we're going to look at declaration and initialization. So this is going
to show the new features in C++ 11 concerned with declaring and initializing variables.
We now have a universal initialization syntax. So you can initialize different types the same way.
So, to do that, we put the initial value inside curly brackets, braces, so int x curly brackets seven is
equivalent to int x equals seven.
And by the way, you can still use the old ones if you like.
It's a fairly tolerant language.
You can also do this with strings.
So instead of having rounded brackets, you can have curly brackets, which may not sound like a big
deal.
Something that is more of a big deal is that you can initialize containers with multiple values.
So if we want to have a vector with elements four, two, three, five and one, we can just write one single
statement which does that. As opposed to older versions where you have to declare the vector as an empty
vector, then push back elements into it.
Or alternatively, you could create the vector with five elements and then assign them all.
Another useful feature is that it fixes a longstanding bug, arguably, that goes back to C. If you have
a numeric type and you try to do some data that's too big for it.
The extra data is just ignored and it'll be truncated.
So in this case, you'd create an int with the value seven and the 0.7 bit is lost. And that is actually
legal.
Although with modern compilers, you may well get a warning.
If you use the modern syntax with curly brackets, then that's not actually allowed.
You'll get a compiler error. And then you'll realize there's a mistake in the code and you need to fix it.
Also, this syntax is much more consistent.
The vector constructor with one argument, creates a vector with that many elements which are value
initialized.
So in this case, we'd have four elements with value zero.
If you have two arguments, then it's the number of arguments and the initial value.
So we'd have four elements with value two. With the new form,
you get exactly what you ask for.
So in this case, we have one element with value four, and we have two elements with value four and two.
And finally, it's also fixes another longstanding C++ annoyance, or maybe it's a fairly small one!
So what exactly does this code do?
You may think that you're creating an object of class Test by calling the default constructor.
In fact, the compiler will think that you're declaring a function which returns an object of class
Test.
And that's known as "the most vexing parse." If you use the new syntax with curly braces, if you have
nothing inside the braces, that indicates no arguments or the default constructor.
And in that case, you are creating an object.
So here is the code. I have written a function to print out the vector elements. That's going to save
as a bit of time in the next example.
This takes the victor by reference to const. As we saw in the video earlier, the last video or the
one before, maybe, this is the best way to pass an object if you just want to look at its data.
And then we iterate over all the elements in the vector and print them out.
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.
It's just a simple way of writing out
iterators.
And if you don't know what iterators are, I'm going to cover those as well!
Okay, so let's try this code out.
So there we are, we get x equals seven, string is "let us begin" and the vector elements are four, two,
three, five and one.
OK.
So here's some code with the narrowing conversion. We're going to try it, first of all, with the old
syntax. So we are going truncate this value of 7.7 down to seven.
So let's see what happens.
So it compiles and runs, and we get y equals seven.
And we also get a compiler warning saying that "conversion from double to int: possible loss
of data."
OK.
And then if we try it with the new syntax, so we comment that one out and we use this one with the curly
brackets.
All right, we actually get an error. "Conversion from table to which requires a loving conversion."
So the compiler doesn't take that. So let's comment this bit out, to avoid confusing things.
And here are the vector definitions.
So let's just check those.
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
one gives four and two.
And then finally, the Test declaration. I've written an empty Test class up here just to make this
compile. And the print function and the includes are the same as they were before.
So there's no problem without that. If I uncomment this, we expect that we'll get a compiler error
because we're defining this symbol test with a lowercase 't' twice.
What we might not expect is that we get an error saying that the previous definition was a function.
So this is actually interpreted as a function definition and this one isn't.
So that demonstrates the difference between the two forms of defining the variable.
Another small but important change, or a useful change anyway.
If you have a template whose parameter type is also a template, you no longer have to put a space between
the two arrows.
If you're using older versions of C++, you have to put a space in there.
Otherwise, the compiler got confused and thought you were trying to do a right shift or do some input
or something like that.
But now the compiler can actually understand it's a nested template.
So let's just check that compiles.
Yep, there we go, no problem.
Of course, if you write code like this, it's going to get pretty unpleasant.
You have lots of angle brackets flying around all over the place, and it gets pretty hard to read.
So the best way to handle that is to write an alias or create an alias for vector of ints
in this case. In older versions of C++, you'd use a typedef. So you put typedef and then the vector
of int, and then we put the alias.
So whenever we put "IntVec", the compiler will replace this by vector of int. And then we can define
a vector of IntVec.
C++ now has a nicer syntax for doing that, or at least I think it's nicer.
So you put using, and then IntVec, and then equals and then we have the vector of int.
The advantage of this is if you have a lot of these definitions and you're scrolling down trying to find one.
It's much easier to look for something on the left hand side of an equal sign than it is for something
at the right of an expression.
At least if you're used to using an alphabet that goes from left to right.
If your native alphabet goes from right to left, you may not see the problem. But you can either.
Each to their own!
So let's check that again.
Okay, that does compile.
And then finally, the famous null pointer.
So C and C++ defined a macro NULL, in capitals, which has the value zero. But the the language doesn't
actually say what the type of NULL is!
So some compilers use int and some use pointer to int.
And some use something else altogether.
In C++ 11, we now have a special type for the NULL pointer.
It can be converted to any other kind of pointer, but it can't be converted to an integer.
And this has actually uncovers quite a lot of bugs in which people were using the null pointer to represent
the number zero.
So here's a little program to try this out (I'm going up in the world again!)
So we have two functions, one of which takes an int and the other one takes a pointer to int.
And we're going to call them with NULL and nullptr as argument.
So if NULL is implemented as an int, it's going to call this one.
If it's implemented as a pointer to int, it's going to call this one.
And if it's implemented as something else, then it might not work at all!
nullprt is defined as being convertible to any kind of pointer, but not to an integer.
So it should call this one.
So let's see what happens.
(Get the focus on the... !)
So the function which takes an int gets called, so NULL is an int, and then the function which takes
a pointer is called so, null pointer is...
Well, it's compatible with pointer to int anyway.
If we'd done this with clang, then they'd both call the function which takes a pointer because clang
implements NULL as points to int.
And if we'd done it with GNU's compiler g++, then we'd have got a compiler error because
NULL is implemented as something else and neither of these functions actually matches.
Okay, so that's it for this video.
As darkness descends upon my recording studio, such as it is!
I'll see you in the next video.
But meanwhile, keep coding.