References#
While pointers are inherited from the C language, C++ introduces a new but similar concept - a reference. References are similar to pointers with a few key differences
References must be set to reference an existing object
References cannot be NULL/nullptr
Once set, references cannot be re-seated (made to reference something else)
The star operator is not required to dereference a reference
References are created by using &
with the type. For example,
std::string my_string = "Hello world!"; // Regular string
std::string & ref_string = my_string; // Reference to my_string
However, given the differences listed above
std::string & empty_ref; // not valid - must reference something
std::string my_string = "Hello world!"; // Regular string
std::string & ref_string = my_string; // Ok, reference to my_string
std::string my_string_2 = "Hello again, world!"; // Regular string
ref_string = my_string_2; // Cannot re-seat reference. Will copy instead.
If we go back to our original pointer example, we can see that taking the address of the reference results in the same address as the pointed-to object. And, like pointers, the original object can be modified via the reference.
#include <iostream> // for std::cout, std::endl
int main(void)
{
int j = 1234;
std::cout << "Value of j: " << j << std::endl;
int & rj = j; // rj references j
std::cout << "Value of rj: " << rj << std::endl;
std::cout << "Address of j: " << &rj << std::endl;
std::cout << "Address of rj: " << &rj << std::endl;
// Change j via rj
rj = 5678;
std::cout << "Value changed!" << std::endl;
std::cout << "New Value of j: " << j << std::endl;
std::cout << "New Value of rj: " << rj << std::endl;
return 0;
}
Value of j: 1234
Value of rj: 1234
Address of j: 0x7fff8727380c
Address of rj: 0x7fff8727380c
Value changed!
New Value of j: 5678
New Value of rj: 5678
It is not common to use references by themselves, but they are very common when passing arguments to functions (which we will see in the next lesson).
Key Points
Pointers are variables that point to an area of memory
Pointers can be used to store homogeneous lists of items
The const
Keyword#
In C/C++, it is possible to mark a variable as constant, such that after setting, the value cannot be changed. Marking a variable as constant can also enable some performance improvements, although these are typically very small. However, they are primarily used to signify intent to other programmers, and can prevent some mistakes.
To create a constant variable, the keyword const
is placed before the type.
const double pi = 3.1415; // Constant double
const std::string my_string = "Hello world!"; // Constant string
my_string = "Another string"; // Error - my_string is const!
Because the constant variable cannot be changed, it must be set at the same time it is declared. Otherwise, you would never be able to set the value!
const int i = 123; // Declare and set
const int j; // j can never be changed after this, so this is invalid.
Constant variables can be very useful in some cases. For example, for storing
physical constants or common strings. As we will see, they are most often
used for declaring objects passed to functions as const
.
Constant references work in a simiar way. Data cannot be changed through a constant reference.
A constant reference can refer to a constant or non-constant variable. However, a non-const reference can only refer to a non-constant variable. Otherwise, we would be able to change constant data just my making a reference to it.
Exercise
What happens when you try to make a non-const reference to const data?
int main(void)
{
const double d = 1.123;
double & d2 = d;
return 0;
}
Solution
A compiler error, of course!
test.cpp: In function ‘int main()’:
test.cpp:4:19: error: binding reference of type ‘double&’ to ‘const double’ discards qualifiers
4 | double & d2 = d;
|
In C++, the const
keyword is called a qualifiers. The compiler is telling
you that making the reference discards the const
qualifier. volitile
is another qualifier, however
it is very rarely used in scientific computing.