Page 1 of 1

C++ : Introduction to References Rate Topic: -----

#1 v0rtex  Icon User is offline

  • Caffeine: db "Never Enough!"
  • member icon

Reputation: 223
  • View blog
  • Posts: 773
  • Joined: 02-June 10

Posted 22 June 2011 - 02:36 AM

*
POPULAR

C++ : Introduction to References

note: this tutorial assumes you have a minor understanding of pointers and reading a quick tutorial about pointers would be beneficial but is not 100% necessary.

References, they are similiar to pointers but have their own advantages/disadvantages in comparison, so for the big question:

What is a Reference?

A reference simply put is a reference to the memory address of another object/variable.
So for example, a reference refers to a variable and thus as such anything you do to the reference is really occuring on the object/variable that the reference is referring to. References are similiar to pointers but they have some distinct differences as will be explained at a later stage.

How do I declare a reference?

A reference is declared via the following syntax:
<Data Type> <Reference Operator> <Reference Name> = <Target>

So for example:

int &rAge = age;


Now to illustrate the above, an example:

#include <iostream>

int main() 
{
using std::cout;
using std::endl;
int age = 18;
int &rAge = age; //reference

cout << "age: " << age << endl;
cout << "rAge: " << rAge << endl;

rAge = 20;

cout << "age: " << age << endl;
cout << "rAge: " << rAge << endl;

age = 24;

cout << "age: " << age << endl;
cout << "rAge: " << rAge << endl;
return 0;
}



After you have run the example code above, there are a few things to note:

  • The datatype of the reference MUST be the same as its target's datatype
  • When a value is assigned to the reference, it is actually being assigned to its target variable.
  • when age is changed, the reference variable's data is changed too!


Now you might be wondering, why is it that when I assign a variable to age, the reference is changed when I have not changed the data in my reference explicitly like so: rAge = 20;.

Well in order to explain this, you must know how to fetch the address of a reference. Now some get confused by this as the address-of operator(&) is used to declare the reference and think that the following will output the reference's address:

#include <iostream>
int main() 
{
using std::cout;
int data = 20;
int &rData = data;
cout << rData;
return 0;
}



Well sadly this is very wrong and many people new to references make this mistake, even though the reference operator is used for more than one operation, it still is necessary when fetching the address of a reference like so:

#include <iostream>
int main() 
{
using std::cout;
int data = 20;
int &rData = data;
cout << "Address in memory of data: " << &data << std::endl;
cout << "Address in memory of rData: " << &rData << std::endl;
return 0;
}




Your output should be similiar to the following:
>Address in memory of data: 0x22ff18
>Address in memory of rData: 0x22ff18



(Your output of the memory addresses may be different depending on your CPU/OS Bitsize etc...)

The simple yet fundamental example above not only shows you how to fetch the address of a reference but demonstrates a fundamental charachteristic of references. The reference refers to the data in its target and as such has the same memory address!

Referring to multiple targets:


This CANNOT be done. references are initialized to refer to their target variable and CANNOT then be reassigned to refer to another target variable at a later stage of your program. a NEW reference must be made for this to occur.

Here is an example of flawed reference logic:
#include <iostream>

int main() 
{
using std::cout; 
using std::endl;

int myAge = 18;
int &rMyAge = myAge;

myAge = 20;

cout << "value of myAge: " << myAge << endl;
cout << "value of myAge reference: " << rMyAge << endl;

int yourAge = 0;
cout << "Enter your age: ";
std::cin >> yourAge;

rMyAge = yourAge;

cout << "value of myAge: " << myAge << endl;
cout << "value of myAge reference: " << rMyAge << endl;
cout << "value of yourAge: " << yourAge << endl;
return 0;
}



re-run the example above a few times, try to figure out why you would not reassign a reference and what is going wrong here in the listing above. Now for the explanation:

The problem with reassigning a reference is that when you do so, it does not do what you probably expect it to. references are initialized when declared and only ever point to the target they were initialized to during their use.
So when you reassign a reference, simply put what you are actually doing is this:
  • make the reference's value now equal to yourAge
  • thus make myAge == yourAge


It would be the same as:
myAge = yourAge;


It does not change the reference's memory address to the new target as the following listing shows:

#include <iostream>

int main()
{
using std::cout;
using std::endl;

int myAge = 18;
int &rMyAge = myAge;

myAge = 20;

cout << "address of myAge: " << &myAge << endl;
cout << "address of myAge reference: " << &rMyAge << endl;

int yourAge = 0;
cout << "Enter your age: ";
std::cin >> yourAge;

rMyAge = yourAge;

cout << "address of myAge: " << &myAge << endl;
cout << "address of myAge reference: " << &rMyAge << endl;
cout << "address of yourAge: " << &yourAge << endl;
//note how myAge reference's address is still myAge's address.
return 0;
}


As you can see the reference's memory address is still the same as what it was initialized to and its value has simply changed and not its address!

Another very valuable thing to note about references is that you should NEVER declare null references as this then means that it has no target to refer to. It is possible but in general is discouraged!

So why use a reference when I have a pointer? They both simply hold the memory address don't they?

Its true, references and pointers for the most part fulfill the same job but I find references cleaner and easier to use however this being said there are certain situations when it is much easier to use a reference compared to a pointer.

Passing a reference to a function:

Normally when you pass data to a function, you pass by value. This simply means that you create a local variable in your function to work with and do not pass its address. A simple example of this is below:

#include <iostream>

int differenceOfAges(int myAge, int yourAge);

int main()
{
using std::cout;
using std::endl;

int myAge = 18;
int &rMyAge = myAge;

myAge = 20;

cout << "address of myAge: " << &myAge << endl;
cout << "address of myAge reference: " << &rMyAge << endl;

int yourAge = 0;
cout << "Enter your age: ";
std::cin >> yourAge;

cout << "address of myAge: " << &myAge << endl;
cout << "address of myAge reference: " << &rMyAge << endl;
cout << "address of yourAge: " << &yourAge << endl;
cout << "value of myAge: " << myAge << endl;
cout << "value of yourAge: " << yourAge << endl;
cout << "Calculating difference of our ages: " << differenceOfAges(myAge,yourAge) << endl;
cout << "Note how the local variables of myAge use space and thus are stored in a different area of memory!" << endl;
return 0;
}

int differenceOfAges(int myAge, int yourAge)
{
using std::cout;
using std::endl;
cout << "Address of local myAge: " << &myAge << endl;
cout << "Address of local yourAge: " << &yourAge << endl;
if (myAge > yourAge) {
return (myAge-yourAge);
}
else {
return (yourAge-myAge);
}
}



In the example above, it is important to notice how the local variables of myAge and yourAge are created in function differenceOfAges() because of the fact that myAge and yourAge are passed by value!

So here is where a reference/pointer comes in, first just to demonstrate the difference in code, we will use a pointer to pass by reference. Passing by reference is what a pointer can do and is useful as no local variable must be declared and this saves space as we are passing the address of the variables and thus the variables can be manipulated directly!

#include <iostream>

int differenceOfAges(int *myAge, int *yourAge);

int main()
{
using std::cout;
using std::endl;

int myAge = 18;
int &rMyAge = myAge;

myAge = 20;

cout << "address of myAge: " << &myAge << endl;
cout << "address of myAge reference: " << &rMyAge << endl;

int yourAge = 0;
cout << "Enter your age: ";
std::cin >> yourAge;

cout << "address of myAge: " << &myAge << endl;
cout << "address of myAge reference: " << &rMyAge << endl;
cout << "address of yourAge: " << &yourAge << endl;
cout << "value of myAge: " << myAge << endl;
cout << "value of yourAge: " << yourAge << endl;
cout << "Calculating difference of our ages: " << differenceOfAges(&myAge,&yourAge) << endl;
cout << "In this example, note how the pointer's addresses are the same and as such no local variable is created thus saving space and is more efficient" << endl;
return 0;
}

int differenceOfAges(int *myAge, int *yourAge)
{
using std::cout;
using std::endl;
cout << "Address of local myAge: " << &*myAge << endl;
cout << "Address of local yourAge: " << &*yourAge << endl;
if (*myAge > *yourAge) {
return (*myAge-*yourAge);
}
else {
return (*yourAge-*myAge);
}
}


Now using pointers to pass by reference is fine and it works amazingly well in most cases however the one complaint that I have about it in comparison to references is that the code in general is alot more messy with a constant need to dereference the pointers is annoying and for example leaving out a * will create errors!

So let us do the same example except with references :


#include <iostream>

int differenceOfAges(int &myAge, int &yourAge);

int main()
{
using std::cout;
using std::endl;

int myAge = 18;
int &rMyAge = myAge;

myAge = 20;

cout << "address of myAge: " << &myAge << endl;
cout << "address of myAge reference: " << &rMyAge << endl;

int yourAge = 0;
cout << "Enter your age: ";
std::cin >> yourAge;

cout << "address of myAge: " << &myAge << endl;
cout << "address of myAge reference: " << &rMyAge << endl;
cout << "address of yourAge: " << &yourAge << endl;
cout << "value of myAge: " << myAge << endl;
cout << "value of yourAge: " << yourAge << endl;
cout << "Calculating difference of our ages: " << differenceOfAges(myAge,yourAge) << endl;
cout << "In this example, note how reference's address is still the same so just like using a pointer,";
cout << "no local variable is the same but the code looks cleaner and  no need to constantly dereference our pointers!" << endl;
return 0;
}

int differenceOfAges(int &rMyAge, int &rYourAge)
{
using std::cout;
using std::endl;
cout << "Address of local myAge: " << &rMyAge << endl;
cout << "Address of local yourAge: " << &rYourAge << endl;
if (rMyAge > rYourAge) {
return (rMyAge-rYourAge);
}
else {
return (rYourAge-rMyAge);
}
}




Doesn't the above code look much cleaner and less error prone than if we implemented pointers?! :)

Note that although both a pointer and reference pass the address, a pointer passes by reference using the address-of operator and a reference passes a reference. I could go into the difference but that is for another tutorial!

If you still are struggling with the point, here is a simple diagram. Note how the memory addresses are different in passing by value as new local variables are declared and are the same when passing by reference/passing a reference:

Posted Image

(Excuse my amazing artistic abilities)

The differenceOfAges function listings were just an example of how references are efficient in certain situations (namely passing data to functions in this case)

A very important issue surrounding pointers/references is how do I distinguish when to use a pointer and when to use a reference?

There are a few important things so to remember that will help you with this:

  • A reference should never be referring to a null value so if you need to do so, use a pointer
  • A reference can not be reassigned so if you need to point to several things, use a pointer
  • References pass a reference so if you need to manipulate the address of a variable, pass a pointer
  • References can be used to make code look cleaner and simpler and generally are less error-prone but do have limitations


However there are some special cases when you need to use both a pointer and a reference
, note that this is more than possible and is really up to the style of the programmer as there are surely ways around this. An example of declaring both a pointer and reference in a function' parameters would be the following:
int differencesOfAges(*myAge, &yourAge);



It is legal but generally easier to opt to use either pointers or references!
The example above of passing by reference is just one of the advantages of references...
I hope this has explained the advantages/disadvantages of references to an extent and adequately introduced you to references! I might create another tutorial explaining some of the more advanced concepts of references soon!
I hope you have enjoyed the tutorial! :)

Thanks,
v0rtex

This post has been edited by v0rtex: 24 June 2011 - 01:45 AM


Is This A Good Question/Topic? 8
  • +

Replies To: C++ : Introduction to References

#2 vividexstance  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 651
  • View blog
  • Posts: 2,225
  • Joined: 31-December 10

Posted 30 June 2011 - 12:27 PM

When you write a function that is going to change the values of the arguments passed to it, it's actually better to use pointers because what the function does will be more clear. Say you're using a library, you call a function that uses references instead of pointers, if you don't know that the function uses references, it could change your variables, and that might not be what you expected. So, it's actually easier to understand what a function is going to do to the arguments when you use pointers. Now, if the function doesn't change the arguments, you should use const references, which does make the code easier to read, instead of pointers.
Was This Post Helpful? 1
  • +
  • -

#3 PlasticineGuy  Icon User is offline

  • mov dword[esp+eax],0
  • member icon

Reputation: 281
  • View blog
  • Posts: 1,436
  • Joined: 03-January 10

Posted 30 June 2011 - 11:13 PM

You should always assume that a function which takes a non-const reference to a varabile will modify the variable.
Was This Post Helpful? 2
  • +
  • -

#4 vividexstance  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 651
  • View blog
  • Posts: 2,225
  • Joined: 31-December 10

Posted 01 July 2011 - 06:15 AM

I was just saying what Bjarne Stroustrup says in his book. IMO you should never assume anything, when you assume you make an ass out of you and me.
Was This Post Helpful? 0
  • +
  • -

#5 oscode  Icon User is offline

  • D.I.C Regular

Reputation: 109
  • View blog
  • Posts: 257
  • Joined: 24-October 10

Posted 11 July 2011 - 05:26 PM

Hi, creating a NULL reference is not only discouraged, it's dependant on undefined behaviour,

"A reference shall be initialized to refer to a valid object or function.
[Note: in particular, a null reference cannot exist in a well-defined
program, because the only way to create such a reference would be to bind it
to the ``object'' obtained by dereferencing a null pointer, which causes
undefined behavior."
Was This Post Helpful? 2
  • +
  • -

#6 Mrk  Icon User is offline

  • D.I.C Head

Reputation: 29
  • View blog
  • Posts: 66
  • Joined: 03-December 09

Posted 13 July 2011 - 03:02 AM

View Postvividexstance, on 01 July 2011 - 06:15 AM, said:

I was just saying what Bjarne Stroustrup says in his book. IMO you should never assume anything, when you assume you make an ass out of you and me.

As I always like to say, assumption killed the cat!
Was This Post Helpful? 0
  • +
  • -

#7 asm-mad  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 10
  • Joined: 31-May 12

Posted 05 June 2012 - 04:07 AM

Thanks! Helped me a lot.
Was This Post Helpful? 0
  • +
  • -

#8 PlasticineGuy  Icon User is offline

  • mov dword[esp+eax],0
  • member icon

Reputation: 281
  • View blog
  • Posts: 1,436
  • Joined: 03-January 10

Posted 17 June 2012 - 06:06 AM

View PostMrk, on 13 July 2011 - 09:02 PM, said:

View Postvividexstance, on 01 July 2011 - 06:15 AM, said:

I was just saying what Bjarne Stroustrup says in his book. IMO you should never assume anything, when you assume you make an ass out of you and me.

As I always like to say, assumption killed the cat!

I would rather say "assume the worst".
Was This Post Helpful? 0
  • +
  • -

#9 vividexstance  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 651
  • View blog
  • Posts: 2,225
  • Joined: 31-December 10

Posted 25 June 2012 - 10:31 AM

View PostMrk, on 13 July 2011 - 05:02 AM, said:

View Postvividexstance, on 01 July 2011 - 06:15 AM, said:

I was just saying what Bjarne Stroustrup says in his book. IMO you should never assume anything, when you assume you make an ass out of you and me.

As I always like to say, assumption killed the cat!

And here I thought it was curiosity, stupid me.
Was This Post Helpful? 0
  • +
  • -

#10 Lionheart Richard King  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 25-June 12

Posted 26 June 2012 - 12:30 PM

good lesson, i read it after my lecture and i finished my hw okay so i think i got this! thanks!
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1