I am trying to understand how to use reference parameters. There are several examples in my text, however they are too complicated for me to understand why and how to use them.
How and why would you want to use a reference? What would happen if you didn’t make the parameter a reference, but instead left the & off?
For example, what’s the difference between these functions:
int doSomething(int& a, int& b);
int doSomething(int a, int b);
I understand that reference variables are used in order to change a formal->reference, which then allows a two-way exchange of parameters. However, that is the extent of my knowledge, and a more concrete example would be of much help.
Think of a reference as an alias. When you invoke something on a reference, you’re really invoking it on the object to which the reference refers.
When it comes to functions, consider:
Above,
int iis a value and the argument passed is passed by value. That means if we say:iwill be a copy ofx. Thus settingito 5 has no effect onx, because it’s the copy ofxbeing changed. However, if we makeia reference:Then saying
foo(x)no longer makes a copy ofx;iisx. So if we sayfoo(x), inside the functioni = 5;is exactly the same asx = 5;, andxchanges.Hopefully that clarifies a bit.
Why is this important? When you program, you never want to copy and paste code. You want to make a function that does one task and it does it well. Whenever that task needs to be performed, you use that function.
So let’s say we want to swap two variables. That looks something like this:
Okay, great. We want to make this a function, because:
swap(x, y);is much easier to read. So, let’s try this:This won’t work! The problem is that this is swapping copies of two variables. That is:
In C, where references do not exist, the solution was to pass the address of these variables; that is, use pointers*:
This works well. However, it’s a bit clumsy to use, and actually a bit unsafe.
swap(nullptr, nullptr), swaps two nothings and dereferences null pointers…undefined behavior! Fixable with some checks:But looks how clumsy our code has gotten. C++ introduces references to solve this problem. If we can just alias a variable, we get the code we were looking for:
Both easy to use, and safe. (We can’t accidentally pass in a null, there are no null references.) This works because the swap happening inside the function is really happening on the variables being aliased outside the function.
(Note, never write a
swapfunction. 🙂 One already exists in the header<algorithm>, and it’s templated to work with any type.)Another use is to remove that copy that happens when you call a function. Consider we have a data type that’s very big. Copying this object takes a lot of time, and we’d like to avoid that:
However, all we really need is an alias to the variable, so let’s indicate that. (Again, back in C we’d pass the address of our big data type, solving the copying problem but introducing clumsiness.):
This is why you’ll hear it said you should pass things by reference all the time, unless they are primitive types. (Because internally passing an alias is probably done with a pointer, like in C. For small objects it’s just faster to make the copy then worry about pointers.)
Keep in mind you should be const-correct. This means if your function doesn’t modify the parameter, mark it as
const. Ifdo_somethingabove only looked at but didn’t changedata, we’d mark it asconst:We avoid the copy and we say “hey, we won’t be modifying this.” This has other side effects (with things like temporary variables), but you shouldn’t worry about that now.
In contrast, our
swapfunction cannot beconst, because we are indeed modifying the aliases.Hope this clarifies some more.
*Rough pointers tutorial:
A pointer is a variable that holds the address of another variable. For example:
So, if you’ve seen the pointer-version swap function, we pass the address of the variables we want to swap, and then we do the swap, dereferencing to get and set values.