References
Concepts
Section titled “Concepts”- rvalue, lvalue
- Reference
Comprehension questions
Section titled “Comprehension questions”What will happen when this code is run? Why?
Unless
mainis shown explicitly, assume the code appears in a typical main file:#include <iostream>#include <array> // required for std::arrayint main(){// here}
1. Assigning to a numeric literal
Section titled “1. Assigning to a numeric literal”5 = 6;Answer
5 is an rvalue, so it cannot appear on the left-hand side of an assignment.
2. Taking the address of a number
Section titled “2. Taking the address of a number”int* a = &5;Answer
You cannot take the address of an rvalue. You can take the address only of an lvalue (an expression that designates an object), because a numeric literal does not designate an object in memory.
3. Taking the address of an expression
Section titled “3. Taking the address of an expression”int* a = &(5 + 6);Answer
The situation is similar: (5 + 6) is an rvalue.
It is impossible to take the address of an rvalue.
4. Reference from a number
Section titled “4. Reference from a number”int& a = 5;Answer
An int& can bind only to an lvalue—an expression that designates an object—
because a must ultimately refer to an object in memory, not merely a value.
5. Reference from a variable
Section titled “5. Reference from a variable”int a = 5;int& b = a;std::cout << a << std::endl;std::cout << b << std::endl;Answer
Here, b is a reference to a.
The compiler may treat b as another name for a
or implement it internally using a pointer to a.
When reading a value, using the name b is equivalent to using the name a
—both names refer to the same object.
Unlike b, a is an object. When its declaration is executed,
storage is allocated for it, typically on the stack.
5 will be printed 2 times.
6. Assigning a number to a reference
Section titled “6. Assigning a number to a reference”int a = 5;int& b = a;b = 6;std::cout << a << std::endl;Answer
Here, a will be overwritten with 6 through the name b.
7. Overwriting a variable that has a reference
Section titled “7. Overwriting a variable that has a reference”int a = 5;int& b = a;a = 6;std::cout << b << std::endl;Answer
a is overwritten directly.
Since b is a reference to a, reading from b reads from a.
8. Reference from an expression
Section titled “8. Reference from an expression”int a = 5;int& b = a + 7;std::cout << a << std::endl;std::cout << b << std::endl;Answer
a + 7 is an rvalue, not an lvalue.
Since a non-const lvalue reference cannot bind to an rvalue, this code will not compile.
9. Assignment operator applied to a reference
Section titled “9. Assignment operator applied to a reference”int a = 5;int& b = a;b += 7;std::cout << a << std::endl;std::cout << b << std::endl;Answer
b += 7 updates a because b refers to a.
The same value will be printed for both variables (12).
10. Assigning a variable to a reference
Section titled “10. Assigning a variable to a reference”int a = 1;int b = 2;int& c = a;c = b;std::cout << a << std::endl;std::cout << b << std::endl;std::cout << c << std::endl;Answer
c = b does not rebind the reference; a reference cannot be rebound.
In c = b, you can effectively replace c with the object it refers to (a),
giving a = b, which overwrites a with the value from b, 2.
The output will be:
22211. Overwriting the referenced variable after assigning through the reference
Section titled “11. Overwriting the referenced variable after assigning through the reference”int a = 1;int b = 2;int& c = a;c = b;c = 3;std::cout << a << std::endl;std::cout << b << std::endl;std::cout << c << std::endl;Answer
Unlike pointers, references cannot be “redirected”.
This illustrates that c continues to refer to a,
even after the line c = b.
The output will be:
32312. Reference from a dereference
Section titled “12. Reference from a dereference”int a = 1;int* pa = &a;int& b = *pa;*pa = 2;b = 3;std::cout << a << std::endl;std::cout << b << std::endl;std::cout << *pa << std::endl;Answer
int& b = *pa; creates a reference to the object pointed to by pa.
All 3 expressions now refer to the same object, a.
3 will be printed 3 times.
13. Reassigning a pointer after creating a reference from it
Section titled “13. Reassigning a pointer after creating a reference from it”int a = 1;int b = 2;int* p = &a;int& r = *p;p = &b;r = 3;std::cout << a << std::endl;std::cout << b << std::endl;Answer
Reassigning p does not change what r refers to, so r = 3 changes a.
The output will be:
3214. Overwriting a variable through an address and a reference
Section titled “14. Overwriting a variable through an address and a reference”int a = 1;int& b = a;int* c = &b;*c = 2;std::cout << a << std::endl;Answer
You can also obtain an address from a reference.
Here, *c = 2; will overwrite a.
15. References to fields
Section titled “15. References to fields”#include <iostream>
struct Position{ int x; int y;};
int main(){ Position a{ .x = 1, .y = 2 };
Position& ra = a;
int& rx = ra.x; ra.x = 3;
ra.y = 4; int& ry = ra.y;
std::cout << rx << std::endl; std::cout << ry << std::endl;
std::cout << ra.x << std::endl; std::cout << ra.y << std::endl;
std::cout << a.x << std::endl; std::cout << a.y << std::endl;}Answer
References can be created to members of larger objects.
Here, 3 and 4 will be printed everywhere.
16. Reference to a pointer (1)
Section titled “16. Reference to a pointer (1)”int a = 1;int b = 2;int* pa = &a;int*& rpa = pa;pa = &b;*rpa = 3;std::cout << a << std::endl;std::cout << b << std::endl;Answer
You can create references to pointers because pointers are also objects that store addresses.
Here, we replace the address stored in pa.
The reference rpa reflects that change, so dereferencing it accesses b.
*rpa -> *pa -> *(&b) -> b
a will be 1, and b will be 3.
17. Reference to a pointer (2)
Section titled “17. Reference to a pointer (2)”int a = 1;int b = 2;int* pa = &a;int*& rpa = pa;pa = &b;int& rb = *rpa;rb = 3;
std::cout << a << std::endl;std::cout << b << std::endl;Answer
This illustrates that references can be bound to any expression that ultimately yields an lvalue.
rb = 3 will write 3 into b.
18. Size of a reference
Section titled “18. Size of a reference”Is it possible to obtain the size of a reference? What is the size of a reference?
#include <iostream>
int main(){ int a = 6; int& b = a; std::cout << sizeof(b) << std::endl;}Answer
sizeof(b) works, but it gives the size of an int, not a reference.
The size of a reference itself cannot be obtained; its representation is an implementation detail.
Many compilers implement a reference parameter by passing an address, but this is also an implementation detail. Such an address is commonly 8 bytes on modern platforms.
A function needs information from outside its local scope to access a particular variable. Passing its address is a straightforward way to provide that information.
19. Example of using references (1)
Section titled “19. Example of using references (1)”#include <iostream>
void resetAmount(int& amount){ amount = 0;}int main(){ int appleAmount = 6; resetAmount(appleAmount); std::cout << appleAmount << std::endl;}Answer
appleAmount will be overwritten with 0 because a reference to it is passed to the function.
Many compilers implement this by passing the address of the appleAmount variable,
but that detail is hidden from you.
20. Example of using references (2)
Section titled “20. Example of using references (2)”#include <iostream>
struct Arm{ int power;};
void increasePower(Arm& arm){ arm.power += 1;}
int main(){ Arm arm { 1 }; increasePower(arm); std::cout << arm.power << std::endl;}Answer
You can pass references to struct objects to a function. Here, the function increases the power.
21. auto makes a copy
Section titled “21. auto makes a copy”int a = 5;auto b = a;b = 6;std::cout << a << std::endl;Answer
auto figures out the type (int) but not the reference:
b is a separate object holding a copy of a.
b = 6 overwrites only the copy, so 5 will be printed.
22. auto& makes a reference
Section titled “22. auto& makes a reference”int a = 5;auto& b = a;b = 6;std::cout << a << std::endl;Answer
auto& figures out int and keeps the reference:
b is another name for a.
b = 6 overwrites a through that name, so 6 will be printed.
Use auto& when you want to change the original —
for example, the elements of an array in a loop —
and const auto& when you only want to read it.