C++
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C++
-
Section 4: Memory Management
-
Section 5: Templates and Generic Programming
-
Section 6: The Standard Template Library
-
Section 7: Modern C++ Features
-
Section 8: Error Handling
-
Section 9: Multithreading
-
Section 10: Operator Overloading and Type Conversion
-
Section 11: Advanced Topics
-
Section 12: Tooling and Build Systems
-
Section 13: Design Patterns in C++
-
Section 14: Interfacing with C and Systems Programming
-
Section 15: Networking and IPC Basics
-
Section 16: Graphics and Game Programming Basics
-
Section 17: The Boost Libraries
-
Section 18: Data Structures and Algorithms in C++
-
Section 19: Practical Projects
-
Section 20: More Concurrency Patterns
-
Section 21: More OOP and Design Practice
-
Section 22: File I/O and Streams
-
Section 23: More Standard Library
-
Section 24: Practice Exercises
-
Section 25: Interview and Algorithm Practice
-
Section 26: Compiler and Language Internals
-
Section 27: GUI and Application Frameworks Overview
-
Section 28: Testing and Quality Practices
-
Section 29: Numerics Library
-
Section 30: Concepts Library (C++20)
-
Section 31: Ranges Library (C++20) In Depth
-
Section 32: More Utility Library
247: std::reference_wrapper
You've probably noticed by now that C++ references are great for passing arguments to functions without copying large objects. But there's a frustrating limitation: references aren't "objects" in the eyes of the language. They can't be rebound once initialized, and more importantly, they can't be stored in a container. You can't have a std::vector<T> where T is a reference.
I ran into this recently while building a simple targeting system for a small game project. I had a bunch of Enemy objects owned by a World class, and I wanted a TargetList that kept track of which enemies were currently being targeted by the player. I didn't want to use std::shared_ptr because the World should remain the sole owner of the memory—I just wanted a way to point to them.
The trap of the reference vector
My first instinct was to keep it simple. I tried to create a vector of references to Enemy objects. It looked something like this:
struct Enemy {
std::string name;
int health;
};
// I wanted to do this:
std::vector<Enemy> targets;
Of course, the compiler immediately started screaming at me. You can't have a std::vector of references because the elements of a vector must be "erasable," which implies they need to be assignable. Since a C++ reference cannot be rebound to a different object after it's created, it doesn't meet the requirements for a container element. It's a common point of friction.
Wrapping the reference
This is where std::reference_wrapper comes in. It's essentially a small class template that holds a pointer internally but behaves like a reference. Because it's a class (an actual object), it can be copied and assigned, making it perfectly legal to put inside a std::vector.
I swapped out my broken vector for this:
#include <vector>
#include <functional> // Required for std::reference_wrapper
#include <iostream>
struct Enemy {
std::string name;
int health;
};
int main() {
Enemy goblin{"Goblin", 30};
Enemy orc{"Orc", 60};
// Instead of Enemy&, we use reference_wrapper
std::vector<std::reference_wrapper<Enemy>> targets;
// We use std::ref() to create the wrapper easily
targets.push_back(std::ref(goblin));
targets.push_back(std::ref(orc));
}
Now the code compiles. std::ref is a helper function that creates a std::reference_wrapper for you. It's much cleaner than typing out the full template name every time you push something into the list.
Interacting with the wrapped objects
One thing that tripped me up for a second was how to actually use the objects once they're in the vector. I tried to access a member directly, like targets[0].health, and the compiler told me std::reference_wrapper has no member named health. I forgot that the wrapper is a shell; it's not the object itself.
To get to the actual Enemy, you have two choices. You can call .get(), or you can rely on the fact that std::reference_wrapper has an implicit conversion operator to the underlying type.
for (Enemy& e : targets) {
// This works because of implicit conversion
std::cout < "Targeting: " < e.name < "\n";
}
// Or, if you need the reference explicitly:
Enemy& firstTarget = targets[0].get();
firstTarget.health -= 10;
I personally prefer the implicit conversion in range-based for loops—it makes the wrapper feel almost invisible. Just keep in mind that std::reference_wrapper doesn't track the lifetime of the object. If the World destroys an Enemy but that enemy is still in your targets list, you've got a dangling reference. It's the same risk as a raw pointer, just with a prettier interface.
📋 Practical Task
Implement a "Selected Units" Manager
You are building a strategy game. You have a Unit class with a unitID and a position. You need to implement a SelectionManager class that can track multiple units without taking ownership of them (the units are owned by a Map class elsewhere).
Requirements:
- Create a
Unitstruct withint unitIDandstd::string type. - Create a
SelectionManagerclass that contains astd::vectorofstd::reference_wrapper<Unit>. - Implement a method
void selectUnit(Unit& u)that adds a unit to the selection. - Implement a method
void printSelection()that iterates through the selected units and prints their ID and type. - In your
mainfunction, create three differentUnitobjects on the stack, select two of them, and callprintSelection()to verify it works.
There are no comments for now.