In this video, we'll learn more about references.
We've already seen how useful references can be when used
as function parameters.
We learned about that in the functions section of the course.
Although a reference may sound similar to a pointer, they're
actually very different.
A reference is an alias for a variable.
So whenever you use the reference, you're actually
using the variable it refers to.
References must always be initialized to a variable when you declare
them, and they can never be null.
Once you initialize a reference, you can't change it so that's an
alias for a different variable.
As mentioned earlier, references are great to use as function parameters.
When you first start out in c++, you might find it useful to think
of a reference as a constant pointer that's automatically
de-referenced when you use it.
We've already seen using references as function parameters,
so let's see some other uses.
References are often used in range-based for loops to
access collection elements inside each iteration.
Here's an example of a range-based for loop that does not use references.
In this case, we have a vector of c++ string objects named stooges, and it's
initialized to Larry Moe and Curly.
Then we use a range-based for loop to iterate through the vector.
At each iteration, we assign Funny to each vector element.
Then we have another range-based for loop that displays the
contents of the stooges vector.
Notice the output, nothing changed.
We didn't change the vector at all, even though we assigned
funny to each element in the loop.
So what's going on.
The problem is that the str variable name in the first loop
is a copy for each of the vector elements as we loop through them.
So we're setting the copy to funny, but we're never changing
the actual elements in the vector.
Now let's see how we can use references to actually
change the vector elements.
Here we have the same example, except that the str variable in
the first loop is now a reference.
In this case, a reference to each of the c++ string objects.
Now str is an alias for those objects, and when we assign Funny to str, we're
actually changing the vector elements.
You can see now that when we display the vector, the elements in the vector
have all indeed changed to funny.
Notice what happens if we add the const qualifier to the loop
variable in the first loop.
Now we're preventing any change to the data in the vector because the
compiler marks it as read-only.
So this code now gives us a compiler error.
This is not what we want since we really do want to
modify the vector elements.
But you can see that the compiler is doing exactly
what you're asking it to do.
It makes sense for us to use the const qualifier in the second
loop, the loop that actually displays the vector elements.
Also by using a reference, we're not incurring the cost of copying each
vector element in each loop iteration.
So in this case, it makes sense to use the const qualifier for the
reference str in the loop when we're displaying the vector elements.
So any attempt to change them would probably be a mistake so we
can have the compiler help us out by making the reference const.
Now any attempt to change the vector element results in a compiler error.
Unless you have a specific reason to copy elements in
range-based for loops, you should use reference variables
to make your code more efficient.
And if you aren't going to modify the collection elements,
make the reference const.
Rather than go over everything we already covered regarding using
references as function parameters, please refer to the section
11 videos and examples where I go over the use of reference
parameters in functions in detail.
We'll head over to the IDE now and see some of these examples in live code.
Okay, so I'm in the IDE.
I'm in the section 12 workspace in the references project.
And this is about as simple an example as I can come up with for references.
So here I've got an integer called num, and I'm initializing it to 100.
And I've got a reference called ref that I'm initializing it to num.
So ref is an alias to num.
So if i display num, I'm going to get a 100.
If I display ref, I'm going to get a 100.
They're aliases.
In this case, the reference is an alias to the num.
Okay, so notice no de-referencing, nothing.
Just use it straight as is, and it's automatically
going to be de-referenced.
Behind the scenes, it's basically a pointer.
That's how it's implemented behind the scenes.
But all that's been abstracted away for you.
So in this case, here, I'm changing num to 200.
So I'm going straight to the variable and changing it to 200.
So when I display num, I'm going to get 200.
And when I display the reference, it's an alias to the number.
Again, I'm going to get 200.
Here, I'm changing num, but I'm changing it through the reference.
So I'm setting it to 300.
Again, they're aliases.
So that's what you get.
Hopefully, that's pretty easy to understand I think.
Now let's do another example that's based on the example
that I did on the slides.
But before we do that, let's run this, so I'll build and run.
And you can see 100 100 200 200 300 300, just what we expected.
Okay, so now let's do an example of using reference parameters
inside range-based for loops, just like we did in the slides.
So let me clear that, and I'll scroll up just a little bit, and I'll
uncomment out this code right here.
Okay, this is the code that worked on the vector of strings.
So here's where we're at.
We've got a vector of string objects right here on line 29, called
stooges, and we're initializing it to Larry Moe and Curly.
Then I've got a range-based for loop.
Now remember, the auto, that's the compiler figure
out what the type of str is.
In this case, the collection is stooges and it's a vector of string.
So str will be a string at each iteration.
And then what we're doing is we're saying str is funny.
So the idea is that or the what the programmer intended to do
was to change Larry Moe and Curly to funny funny funny.
Okay, but it doesn't work.
The reason it doesn't work is because str is a copy.
So each time in, we're making a copy of Larry, a copy of
Moe and a copy of Curly.
So sure, we're changing the copy to funny, but we're not changing
any of these actuals to funny.
So what we can do is and if you notice we have a simple loop
here that just displays them.
And when we run this in a second, you'll see that this
will display Larry Moe and Curly.
Okay, so no changes at all, just like we saw in the slides.
In this next example, what we're doing is we're using a reference here.
You can see the ampersand.
So at each iteration of the loop, str will be a reference to the actual.
So now that str is going to be an alias for each one of these guys
at each iteration of the loop.
So when we say str is funny, now we're really replacing Larry Moe
and Curly with funny funny funny.
So when we come over here and display, we're going to see funny funny funny.
Okay, so we'll run that in a second.
But the other thing we wanted to say was in this example here,
I'm displaying those three string objects that are in the vector.
But in this case, I'm making copies of them.
There's no danger in changing them, right because I've got a copy of them.
So if I do change them like I did here, I'm only changing the copy.
But I'm making copies.
So that's pretty inefficient.
In this case, those string objects are -- they're pretty efficient.
But it could be some user-defined type where making a copy of
it could be pretty expensive.
You're allocating space, and you're making a copy let's say a couple
hundred by 1000 bytes or something.
So it could be very very expensive operation.
In this case, we want to pass that in by reference, like we're doing here.
And -- but the danger with that is that now we can change the
elements, right, which we don't want.
So that's why we use the const.
So this gives us the protection of making those elements read-only, but
it also allows them not to be copied.
In this case, we're just going to create aliases to them.
So very efficient and pretty safe because we can't change them.
Okay, so hopefully that makes sense.
Let me run this real quick.
And you could see the first time through, and I'll move
this slightly over here.
We've got Larry Moe and Curly.
So we didn't change a thing.
We expected funny funny funny.
We got Larry Moe and Curly.
Now when we're using a reference, we do indeed change the actual.
So now we see funny funny funny.
Okay, so give that a try, play around with these, try to create a
reference to a pointer and see if you can figure out how that works.
All right, so that's pretty much it for references.
Remember, I covered how to use reference parameters and how to pass
references to functions in section 11.
There's a whole section there on using reference parameters and
when you use const and so forth.
So I'll see you in the next video.