So far, we've seen that when we pass a parameter into a function,
the default is pass by value.
That means a copy of the actual parameter is made.
We also saw that when we pass an array into a function, we don't make
a copy, instead we use the location of the array, which means we can
change it from within the function.
Well, sometimes we want to be able to change an actual
parameter from within a function.
As we saw with arrays, this is achieved by passing in the
location of the actual parameter.
We can do this in c++ for any variable type not just arrays
by using reference parameters.
Reference parameters create an alias.
So now the formal parameter in the function is an alias
to the actual parameter.
No copy is made.
When you change the formal parameter, you're changing the actual parameter.
This is called pass by reference, and it's really easy to achieve
in c++ by using the ampersand symbol in the parameter list.
Let's see an example.
In this example, we have a function named scale number.
Notice that the parameter list to the function is not an int name num,
it's a reference to an int name num.
That's what the ampersand does so.
Now when we use num in the function body, we're referencing
the actual parameter.
Let's walk through this.
In main, we declare an integer number and initialize it to 1000.
Then we call the scale number function and pass in the
actual parameter number.
We now transfer control to the scale number function since the
formal parameter in the scale number function is a reference parameter.
This means that num is an alias for number.
If we change num, we're changing number.
Behind the scenes, the location of numbers being
passed into the function.
So the code in scale number checks to see if the number
is greater than one 100.
In this case, it is.
It's one 1000.
So we set num to 100, and the function completes.
When we return to main and display number, it will display 100.
Pass by reference can be super useful for several reasons.
First, it allows us to change an actual parameter if we need to.
Second, we don't make a copy of the parameter, which
could be large and take time.
But we have to be aware of potentially unwanted changes.
Let's see how we could swap two numbers using pass by reference.
In this example, we're writing a function that swaps the values of
the two integers passed into it.
Take a look at main.
X is 10 and y is 20.
X and y are first displayed, and we get 10 20,
just as we expect.
Then we call swap and pass in x y.
Then we display x and y again.
Now they're 20 and 10.
We swap them.
Look at the function definition and notice that both a and
b are reference parameters.
So when I call this function with x and y, a and b become
aliases to x and y, respectively.
In the body of the function, I set temp to a, then a
to b, and then b to temp.
And we've swapped the two values that were passed into us.
What do you think would happen if we didn't use pass by reference
and we used pass by value?
Well, the actuals would be copied, so we would swap the copies in
the function and then return.
When we get back to main, the actuals haven't changed since
we were working with copies.
Let's talk a bit about how parameters are passed into functions.
Let's see what happens when we pass in a vector object to a function.
In this case, I have a function called print, and it
expects a vector of integers.
Notice that in this case we're using pass by value.
Inside the print function, I simply use a range based for loop and display
the vector elements, pretty easy.
But there's one issue with this code that is we're using pass by value.
So we're making a complete copy of the vector object in the function.
So the formal parameter v will be a copy of the actual
parameter data in this case.
In order to make a copy, we need to allocate storage and copy values over.
If the vector is very large, we could run it to
performance and storage issues.
So why don't we use pass by reference instead so we can avoid the copy.
Let's do it.
Notice that now I'm using pass by reference since I've declared the
formal parameter v as a reference parameter using the ampersand.
The output of this program is exactly the same as before,
but we avoid the storage and copy overhead of pass by value.
But there is one issue, since I'm using pass by reference,
the print function could change the value of the vector.
It could even erase the entire vector.
This is probably not a good idea.
So let's tell the compiler that this is a constant reference.
So now I've added the const keyword to the parameter.
Now I've told the compiler to use pass by constant reference.
So if I try to make any changes to the formal parameter v in the
function, I will get a compiler error.
This is really the best of both worlds since we're more efficiently passing
information to the function, but we're still ensuring that the function
can't change the data by mistake.
Let's head over to the IDE and see this in action.
Okay, so now I'm in the IDE, and I'm in the section 11 workspace
in the pass by reference project.
This is the same project that we used when we did pass by value.
The only thing I've changed is I've made the parameters
reference parameters now.
So you can see the way I did that was just by including that ampersand.
Now these are the same function prototypes I've just named the
functions pass by ref1 rather than pass by value, as we had before.
Okay, so I've got three pass by reference functions and just a
simple print vector function that displays a vector element by element.
Pass by reference1 expects a reference to an integer, pass by reference2
a reference to a string, pass by reference3 a reference to a vector.
And then the print vector function expects a reference to
a constant vector because I don't want to be able to change the
vector from the print function.
Now I've implemented all of these functions and basically
the code hasn't changed from before I set number to a 1000.
I set the string to change and I clear all the elements out of there.
Now if you remember before, we printed a value, we called
the function, we came back and the old value was still there.
Well, now it's totally different because we're
passing an alias to the value.
Okay, so let's go through these examples.
Here, in main, I've got numb initialized to 10 and another
num initialized to 20.
So now what I'm doing is I'm calling pass by ref1.
And I'm passing num into it.
So before I call it, I expect this to display a 10.
But then after I call it, I don't expect the 10 anymore
because I've passed a reference.
Instead, if you look at pass by ref1, num is a 1000.
So I expect num to change.
All right, so let me run this, and then we'll walk through
exactly what's going on.
There you go.
Before calling passed by ref1, we have a 10.
After calling pass by ref1, we have a 1000.
If you remember the way it was with call by value we had 10 and 10.
All right, so let's see what's really going on here.
Let me scroll up just a little bit.
There we go.
Okay, so I'm in main, and I've got num is 10.
And I'm displaying it right here, right.
So that's going to display a 10 in that output statement right here.
But then I'm calling pass by ref.
So I'm going to call pass by ref1 over here, and it has a variable.
And if you remember what that variable was, let me
scroll up, it's right here.
And it's also called num.
Remember, this could be any other name.
They just happen to be the same name in this case.
So that's got a variable in there called num.
And right here, what's happening is when I pass this
num into it, then this num now becomes an alias to that num.
Okay, and again, don't worry about the names.
I'm going to use a different name next time.
But it's common to many times use the same name, so
don't let that confuse you.
And then in here I'm saying num equals I believe it was a 1000.
So what's happening is this is an alias to this number.
So this guy's going to change to a 1000.
Real, real different to call by value.
Okay, so in this case, we are really passing in the location
of the number behind the scenes.
But we don't have to worry about it because syntactically
it's the same as call by value.
Let's take a look at another example here.
I'll scroll down just a little bit.
And here we've got the same call to pass by ref1 except we're
passing in another number, right.
In this case, another number is 20.
So this will display a 20.
And when I get back, it will have changed also.
There it is, 10 1000.
Now we've got another num was 20, and now it's a 1000.
So you can see that we're passing that by reference and the alias is actually
referring to the actual parameter.
That's the important part to really understand here.
In this example, let's take a look at that.
If you recall this one, let me scroll up just a little bit so you can see
it right here, pass by ref2 expects a reference to a string, and it
just assigns changed to that string.
Okay, so let's walk through this one and see what we can expect.
In this case, I've got this variable right here name, which
is Frank and it's in main, and it's a string object, right.
Then I call pass by ref2.
So here's passed by ref2, and it has a variable over there called
s, that's the formal parameter.
And what we're doing here is we're passing by reference, so we're
passing name over here and this s will now be an alias to name.
So it's really referring to the actual parameter.
Remember, this right here is the actual parameter.
So now when I change this to change, nothing happens over here,
it's actually happening over here.
So this is gone.
It's now changed.
So when this function is done, my actual parameter has changed,
in this case, to changed.
Okay, so let's run this example, and we'll be able to see that
that string really does change.
You see that right there, name before calling pass by ref2 is Frank.
Name after calling pass by ref2 is changed, pretty easy.
It's really up to you.
And when you're designing, do you need the actual changed or not?
If you do need a change, you pass it by reference.
If you don't need a change, you do pass by value.
Sometimes pass by value is very expensive, as I mentioned before.
So you want to pass by reference and then qualify it to be constant.
And that's what we'll do in the print function a little bit.
But let's take a look at this one here.
Okay, so this is the last example we'll look at right here.
Remember, we're calling passed by rer3 and pass by ref3 all it
does is clears out that vector.
So it's going to remove all the vector elements.
It's going make the vector empty.
Okay, so let's do that.
All right, so we're here.
This is stooges.
And again, stooges is declared in main.
So stooges is basically three strings: Larry, Moe and Curly.
And they're in a vector.
Okay, so now I'm going to print the vector.
And I'm going to pass stooges into print vector.
Now the vector is also expecting a reference.
In this case, a constant reference so I can't change anything.
So what happens is when I call print,
so when I call print vector,
there's a variable over there called v.
And since I'm doing pass by reference, this refers to this.
So whenever I deal with I do any operation on v, it's affecting
the stooges vector, right.
That would be the case.
But since this is const, this is read-only.
There's no changes allowed.
But I avoid the whole copy issue which is important.
All right, so that takes care of print.
Now when I call pass by reference3, I do exactly the same thing, right.
So I call pass by reference3.
I've got my vector, and it's also pointing to stooges.
Now when I say v.clear, I'm clearing this out now, right.
So stooges is empty now.
When this when this function is done, it's gone.
And my vector is empty.
So when I print it out again right here, you'll see nothing print.
If you recall in the pass by value, it printed out Larry
Moe and Curly again, right.
Here nothing.
So let's run this, and you could see right here stooges before calling
pass by ref3: Larry, Moe Curly.
After calling it, empty.
Why is it empty because pass by ref3 cleared out that vector.
It deleted all the elements.
And because I'm passing by reference, it's really
affecting the actual object.
If I didn't want this to happen, I would make this const in which case
this won't compile anymore because you're not allowing me to change the
vector, which is what this is doing.
You'll get a lot of chances to play with this in the challenge
at the end of the section.
But that's passed by reference, we can use it with simple primitive types
or we can use it with object types.
It basically works the same way.
Just think of it as an alias to the actual parameter.