C++ Tutorial
References for Built-in Types - 2020
A reference variable is actually just a pointer that reduces syntactical clumsiness related with pointers in C (reference variables are internally implemented as a pointer; it's just that programmers can't use it the way they use pointers).
As a side note, a reference must refer to some object at all times, but a pointer can point to NULL. In this way, references can be more efficient when we know that we'll always have an object to point to, because we don't have to check against NULL
void doubleRef(int &a;, int &b;) { a *= 2; b *= 2; } void doublePtr(int *a, int *b) { *a *= 2; *b *= 2; } int main() { int x = 1, y = 10; doubleRef(x,y); // 2, 20 doublePtr(&x;, &y;); // 4, 40 return 0; }
A reference is an alias for an object. C++ reference allows us to create a new name for an existing object. It also allows us to manipulate an object in a similar way of using pointer without pointer syntax.
In practice, references are primarily used as parameters to a function such as an object passed into a function. But in this chapter we'll only deal with references for built-in types.
A reference must be initialized. Once defined, a reference cannot be made to refer to another object and this is why it must be initialized.
int ival = 128; int &refval; = ival; // refval is a reference to ival int &refval2; // Error: a reference must be initialized
By changing the value of reference, we can change the value of the referenced original variable. In other words, any access and modification done through the new reference affect the original.
refval++; // ival is now 129.
Though a reference is a kind of pointer, it is not correct to initialize it to the address of an object, as we would do a pointer.
int ival = 128; int &refval; = &ival; // Error: refval is of type int, not int*
How about assigning a non-addressable value (such as literal constant) to the reference?
int &refval2; = 256;
Then, we'll get the error message:
error C2440: 'initializing' : cannot convert from 'int' to 'int &'or
error: initial value of refrerence to non-const must be an lvalue
The references that we've been using so far are lvalue references-references to lvalues. The term lvalue refers to things that can be on the left side of an assignment expression such as named objects or objects allocated on the stack or heap-things with a defined storage location. The term rvalue refers to things that can occur only on the right side of an assignment expression such as literals and temporaries which are intended to never be modifiable. The lvalue references can only be bound to lvalues but not rvalues.
So, the reason why we got the error in the line
int &refval2; = 256;is because 256 is an rvalue.
However, we can bind an rvalue to a const lvalue reference (const reference):
int const &refval2; = 256;
Note that we can also have lvalues that aren't variables:
int x; int& getReference () { return x; } getReference() = 99;
Here, getReference() returns a reference to a global variablestored in a permanent location. So, we should be aware that a function call can be an lvalue if and only if the return value is a reference.
The following code compiles and produces an output for x = 0:
#include <iostream> int main() { int x = int(); // initializes x = 0 std::cout << x << std::endl; return 0; }
However, the code below does not compile because the int() is not an lvalue, and can't be assigned (no physical location to store a value):
#include <iostream> int main() { int x = int()= 99; std::cout << x << std::endl; return 0; }
Once again, reference should be initialized via lvalue. In other words, it should be initialized via variable, not via literal value. This also applies to the pointer to a reference as shown in the code below:
int main() { int x = 3; // ref should be initialized via variable // int ℞ = 3; // Error int ℞ = x; // OK // pointer to a reference should be initialized via pointer // int*& prx = &x; // Error int *px = &x; int *&prx; = px; // OK return 0; }
A reference almost always refers to the variable with which it was initialized. C++ references allow us to create a new name for an existing object. We can't resign a reference to refer to another variable. So, for example, the result of the code below might not be obvious:
int herWeight = 110; int& WeightOfHermione = herWeight; int WeightOfHarry = 170; WeightOfHermione = WeightOfHarry; WeightOfHarry = 200;
The line
WeightOfHermione = WeightOfHarry;does not reassign the reference WeightOfHermione so it refers to WeightOfHarry because a reference can't be reassigned. However, because WeightOfHermione is just another name for herWeight, the code
WeightOfHermione = WeightOfHarry;is equivalent to
herWeight = WeightOfHarry;which assigns 170 to herWeight. The final outcome: herWeight becomes 170 and WeightOfHermione still refers to herWeight and it is 170 not 200.
And How about assigning an object of a different type (assuming there is a conversion from the one type to the other) to the reference?
double dval = 3.14; int &rval3; = dval;
Again, we'll get similar error:
error C2440: 'initializing' : cannot convert from 'double' to 'int &'
This is another important feature of reference. For functions, when it is used to match arguments with parameters. With value parameters, we said that implicit type conversion occurs (the value of the argument is converted, if possible, to the data type of the parameter). In contrast, reference parameters require that the matched items must have exactly the same data type.
But things are different if it's a const reference.
int const &rval4; = 1024; double dval = 3.14; int const &rval5; = dval;
The conversion is done by the compiler using temporary object. This is a deliberate exception on the part of the standard, introduced before we had C++11 - value references in order to allow us to pass temporaries to functions taking references. Because this provision allows implicit conversions, we can write things like this:
void print(std::string const& s); print("implicit_conversions - rvalue references");
For rvalue references, please visit C++11 - rvalue references.
Two primary differences between a reference and pointer are:
- a reference must always refer to an object
- The assignment of one reference with another changes the value of the object referenced but not the reference itself
Following code is an example for pointers:
int i1 = 1, i2 = 2; int *ptr1 = &i1;, *ptr2 = &i2; p1 = p2;
Here, p1 and p2 now both address the same object whose value is 2. This can be a significant source of program error.
But for references,#include <iostream> using namespace std; int main() { int i1 = 1000, i2 = 2000; int &r1; = i1; int &r2; = i2; cout << "r1=" << r1 << " r2=" << r2 << endl; cout << "&r1;=" << &r1; << " &r2;=" << &r2; << endl; r1 = r2; cout << "r1=" << r1 << " r2=" << r2 << endl; cout << "&r1;=" << &r1; << " &r2;=" << &r2; << endl; }
with outputr1=1000 r2=2000 &r1;=0017FF28 &r2;=0017FF1C r1=2000 r2=2000 &r1;=0017FF28 &r2;=0017FF1C
It is i1, the value referenced by r1, that is changed, and not the reference. After the assignment, the two references still refer to their original objects. -
Pinter Reference Assignment to a pointer changes the pointer's value but not the pointed-to-value. Assignment to a reference changes what the reference refers to but not the reference itself. Assignment of pointers does not deep copy, it just assigns to the pointer object itself. Assignment of references does deep copy, it assigns to the referred-to object. We cannot make a reference refer to a different object after initialization. To get a pointer we need to use new or & To access an object pointed to by a pointer, we need to use * or [] - Can't switch a reference to refer another.
A reference must be initialized where it is defined. After that, it cannot be used to refer to anything else.char &myRef; = *(new char); myRef = 'x'; delete &myRef; &myRef; = *(new char); Not allowed
-
See also, Pointers vs References
For pointer example:
int *ptr = 0;Here, the pointer, ptr, currently addresses no object, but for reference,
const int &r; = 0;internally, following takes place and the reference, r, still refers an object.
int temp = 0; const int &r; = temp;
For references with a structure and classes, please try other chapters of this tutorial.
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization