What is reference?
Const pointers
Reference to variable
#include <iostream> using namespace std; int main () { int x = 1; int &y = x; int *z = &x; cout << "Initially x " << x << " y " << y << " z " << z << " z val " << *z << endl; x++; cout << "After x++ x " << x << " y " << y << " z " << z << " z val " << *z << endl; y++; cout << "After y++ x " << x << " y " << y << " z " << z << " z val " << *z << endl; z++; cout << "After z++ x " << x << " y " << y << " z " << z << " z val " << *z << endl; }
Output:
Initially x 1 y 1 z 0x7ffc764b6284 z val 1 After x++ x 2 y 2 z 0x7ffc764b6284 z val 2 After y++ x 3 y 3 z 0x7ffc764b6284 z val 3 After z++ x 3 y 3 z 0x7ffc764b6288 z val 1984651908
Reference to pointer
So, it is certainly possible to have references to arrays, even though the syntax is awkward. It may be easier to begin with a reference to a pointer, which basically just follows the normal reference syntax:
int* p = new int[10]; int* &q = p; // q is a reference to p, an int* p[9] = 999; cout << q[9]; // 999
Reference to an array
And if you really want a reference to an array, it is like this:
int a[10]; int (&b) [10] = a; // b is a reference to a, an int[10] a[8] = 888; cout << b[8]; // 888
The type of a here is int[10] (not just int[]); in C++ the size of an array is part of the type, i.e. int[10] is not the same type as int[5]. If raw arrays decay into pointers, size should be passed explicitly along with them. But, here b is a reference to an actual array instead of decaying into pointers.
If you are tempted to write just "int &b[10]", it will mean one dimensional array b of references to type int[10]. However, int (&b)[10] means a reference to one dimensional array of type int[10].
The bracket around &b is needed. Due to how C++ puts the square brackets after the variable name, this syntax is a bit weird.
Click here to learn more about reference to an array.
Reference to an array element
You can also have reference to individual array entries, i.e.
int a[10]; int& b = a[1]; // b is a reference to a[1]
But you cannot have an array of references, i.e. an array where each entry is a reference to something different.
What is pointer ?
A pointer in C++ is a variable that holds the memory address of another variable.
Other Differences
- Reference to array can't be null whereas raw pointer can be null.
- If it is a raw pointer, it can be incremented. References can't be incremented to point to the next address.
The last difference is the crucial difference.
Pass-by-value
/* Pass-by-value into function (TestPassByValue.cpp) */ #include <iostream> using namespace std; int square(int); int main() { int number = 8; cout << "In main(): " << &number << endl; // 0x22ff1c cout << number << endl; // 8 cout << square(number) << endl; // 64 cout << number << endl; // 8 - no change } int square(int n) { // non-const cout << "In square(): " << &n << endl; // 0x22ff00 n *= n; // clone modified inside the function return n; }
Pass-by-reference with pointer
/* Pass-by-reference using pointer (TestPassByPointer.cpp) */ #include <iostream> using namespace std; void square(int *); int main() { int number = 8; cout << "In main(): " << &number << endl; // 0x22ff1c cout << number << endl; // 8 square(&number); // Explicit referencing to pass an address cout << number << endl; // 64 } void square(int * pNumber) { // Function takes an int pointer (non-const) cout << "In square(): " << pNumber << endl; // 0x22ff1c *pNumber *= *pNumber; // Explicit de-referencing to get the value pointed-to }
Pass-by-reference with reference
/* Pass-by-reference using reference (TestPassByReference.cpp) */ #include <iostream> using namespace std; void square(int &); int main() { int number = 8; cout << "In main(): " << &number << endl; // 0x22ff1c cout << number << endl; // 8 square(number); // Implicit referencing (without '&') cout << number << endl; // 64 } void square(int & rNumber) { // Function takes an int reference (non-const) cout << "In square(): " << &rNumber << endl; // 0x22ff1c rNumber *= rNumber; // Implicit de-referencing (without '*') }
Recall that references are to be initialised during declaration. In the case of function formal parameter, the references are initialised when the function is invoked, to the caller's arguments.
References are primarily used in passing reference in/out of functions to allow the called function accesses variables in the caller directly.
Lvalue reference
Can an rvalue be converted to lvalue? Nope. It's not a technical limitation, though: it's the programming language that has been designed that way.
In C++, when you do stuff like
int y = 10; int& yref = y; yref++; // y is now 11
you are declaring yref as of type int&: a reference to y. It's called an lvalue reference. Now you can happily change the value of y through its reference yref.
We know that a reference must point to an existing object in a specific memory location, i.e. an lvalue. Here y indeed exists, so the code runs flawlessly.
Now, what if I shortcut the whole thing and try to assign 10 directly to my reference, without the object that holds it?
int& yref = 10; // will it work?
On the right side we have a temporary thing, an rvalue that needs to be stored somewhere in an lvalue.
On the left side we have the reference (an lvalue) that should point to an existing object. But being 10 a numeric constant, i.e. without a specific memory address, i.e. an rvalue, the expression clashes with the very spirit of the reference.
Note: use reference over pointer, use pointers for non-owning parameters that may be null.
Reference
University of Leicester's Master's Lecture
Comments
Post a Comment