When we pass values to a function or return values from a function that is exactly what we are doing. Passing or returning a value. What happens is that a copy of the variable’s value is made, and sent into the function where it is used. Nothing happens to the actual variable itself. C++ references allow us to work around this. But why would we even want to?
What are references and why should I use them?
You can think of a variable as a storage box in the computer’s memory. When we use a variable as a function argument we are not passing the storage box but instead we are writing a note of the value contained in that storage box and passing the note to the function. Certainly, the function can find that value useful and do computations with it but nothing will happen to the storage box itself – it still holds the same value after the function returns. Often this is a good thing but sometimes it would be useful to work on the actual variable itself.
The consequences of this situation are as follows. If we want the function to make a permanent change to a variable we need make sure to return the value and then assign it. This is not always simple. Another way of working would be useful.
When a copy is made, to pass in as an argument or return from the function, it uses up processing power and slows down our game. For a simple variable or even an object of a class, this is not too much of a problem. For a large object, perhaps a level design or many objects, perhaps all the bullets in a bullet-hell style game, this can be a big problem. Another way of working seems more vital still.
How to use C++ references
References are the solution “other way” to which I refer. A reference is a special type of variable. A reference “refers” to another variable. An example will be useful.
int numZombies = 100;
int& rNumZombies = numZombies;
In the code above we declare and initialize a regular int called numZombies. We then declare and initialize a int reference called rNumZombies. The reference operator & that follows the type, determines that a reference is being declared. The r prefix at the front of the reference name is optional but useful for remembering that we are dealing with a reference.
Now we have a
numZombies which stores the value 100 and a
int reference called
rNumZombies that refers to
Anything we do to numZombies can be seen through rNumZombies and anything we do with rNumZombies,we are actually doing with numZombies. Take a look at the next code.
int score = 10;
int& rScore = score;
In the previous code, we declare a
score. Next, we declare a
int reference called
rScore that refers to
score. Remember that anything we do to
score can be seen by
rScore and anything we do with
rScore is actually being done to
Therefore, when we increment score like this:
The score variable now stores the value 11. In addition, if we were to output rScore, it would also output 11. The next line of code is:
Now score actually holds the value 12 because anything we do with rScore is actually being done to score.
What is happening when we use references is that the compiler is doing work behind the scenes for us. If you want to know exactly what is happening and don’t like all this magic stuff then the next tutorial on the subject of pointers will make things clearer.
Notice I said clearer and not clear. The only way to begin to fully understand all this stuff about references is to use them repeatedly. Don’t make the mistake of trying to fully understand everything before you start using them.
But simply put, you can consider a reference as storing a place/address in the computer’s memory. That place in memory is the same place where the variable it refers to stores its value. Therefore, an operation on either the reference or the variable has exactly the same effect.
For now, it is much more important to remember why you use references. There are two reasons to use references and here they are again.
- Manipulating or reading the value of a variable/object in another function which is otherwise out of scope
- Passing in or returning to/from a function without making a copy (and therefore more efficiently)
Just because it is not essential to fully understand references before we use them it doesn’t mean we shouldn’t try.
Making references clearer with a full example
Take a look at this completely hypothetical and pointless code that will hopefully clarify this reference stuff.
void add(int n1, int n2, int a);
void referenceAdd(int n1, int n2, int& a);
int number1 = 2;
int number2 = 2;
int answer = 0;
add(number1, number2, answer);
// a still equals zero because it is passed as a copy
// Nothing happens to answer in the scope of main
referenceAdd(number1, number2, answer);
// Now a equals 4 because it was passed by reference
// When the referenceAdd funtion did this:
// answer = num1 + num 2;
// It is actually changing the value stored by a
// Here are the two function definitions
// They are exactly the same except that
// the second passes a reference
add(int n1, int n2, int a)
a = n1 + n2;
// a now equals 4
// But when the function returns a is lost forever
referenceAdd(int n1, int n2, int& a)
a = n1 + n2;
// a now equals 4
// But a is a reference!
// So it is actually answer, back in main, that equals 4
The previous code begins with the prototypes of two functions, add and referenceAdd. The add function takes three int variables and the referenceAdd function takes two int variables and a int reference.
When the add function is called, the variables number1, number2, and answer are passed in, a copy of the values is made and new variables local to add ( n1, n2 and a) are manipulated. As a result of this answer, back in main remains at zero.
When the referenceAdd function is called number1 and number2 are again passed by value. However, the variable answer is passed by reference. When the value of n1 added to n2 is assigned to the reference a, what is really happening is that the value is assigned to answer back in the main function.
It is probably obvious that we would never need to actually use a reference for something this simple. It does, however, demonstrate the way that passing by reference works.
Tell me once more why I should use references
The previous code while pointless, demonstrated how a reference can be used to alter the value of a variable in one scope using the code in another. As well as being extremely convenient, passing by reference is also very efficient because no copy is made. Soon we will make a game using references that are actually useful. It is just handy to see the theory before you use it for real.
The problem with references
Not so much a problem as a limitation. You must assign the reference to a variable at the time you create it. This means it is not completely flexible. When we look at C++ pointers in the next tutorial we will overcome this limitation.
We will use references in the next full game project coming soon.