Lesson 22
References
Covers reference declaration, syntax, sharing memory, passing by reference, const references, and comparisons with pointers.
Lesson content
What are References in C++?
A reference is another name (or alias) for an existing variable. Once a reference is created, both the original variable and the reference refer to the same memory location.
Think of a reference like a nickname for a person. Whether you call someone by their full name or nickname, you're still referring to the same individual.
Why do references exist?
- Avoiding unnecessary copies
- Allowing functions to modify original variables
- Making code cleaner than pointers in many situations
- Improving program efficiency
Real-world use cases
- Passing function arguments efficiently
- Returning values from functions
- Range-based for loops
- Operator overloading
- Working with STL containers
- Avoiding copies of large objects
Prerequisites
- Variables
- Data types
- Functions
- Basic C++ syntax
- Memory basics
- Difference between values and variables
What is a reference?
A reference is declared using the & symbol.
int x = 10;
int& ref = x;- x is the original variable
- ref is a reference to x
- Both share the same memory location
Syntax
dataType& referenceName = variable;
int number = 100;
int& value = number;Reference shares memory
int x = 20;
int& y = x;
y = 50;
// x is now 50, since y and x refer to the same memoryReferences cannot be null
Unlike pointers, references must always refer to a valid object and must be initialized when declared.
int* ptr = nullptr; // valid for pointers
int x = 10;
int& ref = x; // valid
int& ref2; // invalid, must be initializedReferences cannot be changed
int a = 10;
int b = 20;
int& ref = a;
ref = b;
// a = 20
// b = 20Many beginners think ref now refers to b. Actually, the assignment copies the value of b into a. The reference still refers to a.
Reference vs copy
int x = 10;
int y = x;
y = 50;
// x = 10
// y = 50int x = 10;
int& y = x;
y = 50;
// x = 50
// y = 50Passing by reference
void increment(int number)
{
number++;
}
// The original variable is not modified.void increment(int& number)
{
number++;
}
// Now the original variable changes.Const references
Sometimes you want to avoid copying but also prevent modification.
void print(const string& name)
{
cout << name;
}- No copy
- Faster
- Safe from modification
This is the preferred way to pass large objects that don't need to be changed.
Example 1: Creating a reference
#include <iostream>
using namespace std;
int main()
{
int number = 25;
int& ref = number;
cout << number << endl;
cout << ref << endl;
return 0;
}
// Output:
// 25
// 25Example 2: Modifying through a reference
#include <iostream>
using namespace std;
int main()
{
int age = 18;
int& studentAge = age;
studentAge = 21;
cout << age << endl;
return 0;
}
// Output: 21Example 3: Pass by reference
#include <iostream>
using namespace std;
void addFive(int& value)
{
value += 5;
}
int main()
{
int number = 10;
addFive(number);
cout << number << endl;
return 0;
}
// Output: 15Example 4: Using a const reference
#include <iostream>
#include <string>
using namespace std;
void display(const string& message)
{
cout << message << endl;
}
int main()
{
string text = "Welcome to C++";
display(text);
return 0;
}Example 5: Range-based for loop with references
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> numbers = {1, 2, 3};
for (int& value : numbers)
{
value *= 2;
}
for (const int& value : numbers)
{
cout << value << " ";
}
return 0;
}
// Output: 2 4 6Common mistakes and pitfalls
- Declaring an uninitialized reference (int& ref;). Fix: int x = 5; int& ref = x;
- Binding a non-const reference to a literal (int& ref = 10;). Fix: use const int& ref = 10;
- Assuming ref = other; changes what ref refers to. Fix: remember it assigns the value of other to the original variable
- Passing large objects by value unnecessarily. Fix: pass them by const reference when modification isn't needed
- Returning a reference to a local variable. Fix: return by value, or return a reference only to an object that remains alive
Best practices
- Use references instead of pointers when nullptr isn't needed
- Pass large objects by const reference to avoid unnecessary copies
- Use non-const references only when a function needs to modify the caller's object
- Keep reference lifetimes valid; never let a reference outlive the object it refers to
- Use descriptive names to make it clear when a function modifies its arguments
When not to use this
- An object may be absent (nullptr semantics are needed)
- You need to reseat the reference to point to another object later
- Ownership transfer is required (use smart pointers instead)
- You're implementing low-level memory management where pointers are more appropriate
Summary
- A reference is an alias for an existing variable
- References must be initialized when declared
- References cannot be nullptr
- References cannot be reseated to refer to another object
- Changes through a reference affect the original variable
- Passing by reference avoids unnecessary copying
- const references are ideal for reading large objects efficiently
- References are generally simpler and safer than pointers when optional behavior isn't required
Frequently asked questions
What is the difference between a reference and a pointer?
A reference is an alias for an existing object and cannot be null or reseated. A pointer stores an address, can be null, and can point to different objects during its lifetime.
Why are references faster than passing by value?
Passing by value creates a copy of the object. Passing by reference avoids copying, which is especially beneficial for large objects like strings, vectors, and user-defined classes.
Can a reference refer to another reference?
Yes. However, in C++, references are effectively aliases, so a reference to a reference still refers to the original object.
Why use const references?
A const reference avoids copying while preventing accidental modification of the original object. This is the preferred way to pass large read-only objects to functions.
Should I use references or pointers?
Use references when an object is guaranteed to exist and should always be valid. Use pointers when you need optional values, dynamic memory management, or the ability to change which object is being referenced.