References
References and Lifetime
Section titled “References and Lifetime”References are aliases for other variables. This chapter covers references, their relationship to pointers, and object lifetime management.
References vs Pointers
Section titled “References vs Pointers”┌─────────────────────────────────────────────────────────────┐│ References vs Pointers │├─────────────────────────────────────────────────────────────┤│ ││ Reference Pointer ││ ┌─────────────┐ ┌─────────────┐ ││ │ int& ref = │ │ int* ptr = │ ││ │ var; │ │ &var; │ ││ └─────────────┘ └─────────────┘ ││ ││ • Always bound to an object • Can be null ││ • Cannot be reseated • Can be reassigned ││ • No arithmetic • Supports arithmetic ││ • Syntax like regular variable • Needs * to dereference││ │└─────────────────────────────────────────────────────────────┘Basic References
Section titled “Basic References”int value = 42;int& ref = value; // ref is alias for value
ref = 100; // Changes value to 100std::cout << value; // 100
// Reference is not a copystd::cout << &value << std::endl; // Same addressstd::cout << &ref << std::endl; // Same addressReferences in Functions
Section titled “References in Functions”Pass by Reference
Section titled “Pass by Reference”void swap(int& a, int& b) { int temp = a; a = b; b = temp;}
int main() { int x = 5, y = 10; swap(x, y); // x=10, y=5}Return by Reference
Section titled “Return by Reference”std::vector<int> vec = {1, 2, 3, 4, 5};
int& getElement(std::vector<int>& v, size_t index) { return v[index]; // Returns reference to element}
int main() { getElement(vec, 0) = 100; // Modify through reference std::cout << vec[0]; // 100}Warning: Don’t return reference to local variable!
int& badFunction() { int x = 5; return x; // DANGER: x is destroyed when function returns}const References
Section titled “const References”void printValue(const int& value) { // value = 100; // Error: can't modify std::cout << value << "\n";}
int main() { int x = 42; printValue(x); // Pass by const reference
// Can also pass temporaries printValue(100); // Temporary is kept alive for the call}Lvalue and Rvalue References
Section titled “Lvalue and Rvalue References”Lvalue References (&)
Section titled “Lvalue References (&)”int x = 10;int& lref = x; // Lvalue reference - binds to named variable// int& lref2 = 10; // Error: can't bind to rvalueRvalue References (&&)
Section titled “Rvalue References (&&)”int x = 10;int&& rref = 10; // Rvalue reference - binds to rvalue (temporary)int&& rref2 = x; // Error: can't bind lvalue to rvalue ref
// Move semantics use rvalue referencesint&& moveRef = std::move(x); // Cast to rvalueReference to Pointer
Section titled “Reference to Pointer”int value = 42;int* ptr = &value;
int*& refToPtr = ptr; // Reference to pointerrefToPtr = nullptr; // Changes ptr to null
int* const& refToConstPtr = ptr; // Const reference to pointerObject Lifetime
Section titled “Object Lifetime”Automatic Storage Duration
Section titled “Automatic Storage Duration”void function() { int x; // Destroyed when function returns std::string s; // Destructor called}Static Storage Duration
Section titled “Static Storage Duration”void function() { static int count = 0; // Lives for entire program count++;}Dynamic Storage Duration
Section titled “Dynamic Storage Duration”void function() { int* p = new int(42); // Lives until explicitly deleted delete p; // Must manually delete}RAII (Resource Acquisition Is Initialization)
Section titled “RAII (Resource Acquisition Is Initialization)”class File { FILE* file;
public: File(const char* name) { file = fopen(name, "r"); }
~File() { if (file) fclose(file); // Automatic cleanup }};
void function() { File f("data.txt"); // Opens file // Use file...} // File automatically closedLifetime Extension
Section titled “Lifetime Extension”Temporary objects are extended to match reference lifetime:
const std::string& getName() { return "Temporary"; // Temporary is extended}
std::string&& getRvalue() { return std::string("Temporary"); // Must use rvalue ref}Complete Example: Reference Wrapper
Section titled “Complete Example: Reference Wrapper”#include <iostream>#include <functional>
void increment(int& value) { value++;}
void decrement(int& value) { value--;}
int main() { int num = 10;
// Using std::ref to pass by reference through std::function std::function<void()> inc = std::bind(increment, std::ref(num)); std::function<void()> dec = std::bind(decrement, std::ref(num));
inc(); // num = 11 inc(); // num = 12 dec(); // num = 11
std::cout << num << "\n"; // 11
return 0;}Key Takeaways
Section titled “Key Takeaways”- References are aliases - not new variables
- References must be initialized
- References cannot be null
- Use const references to avoid copies
- Rvalue references enable move semantics
- RAII ensures automatic resource cleanup
Next Steps
Section titled “Next Steps”Let’s learn about smart pointers - the modern way to manage dynamic memory.
Next Chapter: 22_smart_pointers.md - Smart Pointers (unique_ptr, shared_ptr)