Passing function objects into std algorithms by reference
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Introduction
Standard C++ algorithms usually take callable objects by value, which means the algorithm receives its own copy. If you need the algorithm to operate on the original function object instead, wrap it with std::ref.
Why Algorithms Normally Copy the Callable
Most standard algorithms are designed to accept predicates, comparators, and functors as regular value parameters. That keeps the interface simple and works well for lightweight stateless callables.
But it also means state changes inside the functor often happen on a copy rather than on the original object.
std::for_each increments its internal copy of counter. The original object outside the algorithm does not necessarily change.
Use std::ref to Pass by Reference
If you want the algorithm to invoke the original object, use std::ref.
std::ref creates a reference_wrapper, which is copyable but still forwards calls to the original object.
When Reference Passing Matters
Passing the functor by reference is useful when:
- The functor carries state that should be updated
- Copying the functor would be expensive
- You want several algorithm invocations to share the same stateful callable
For tiny stateless lambdas, none of this usually matters. The default copy behavior is fine and often preferable.
Lambdas and Captures
Lambdas follow the same idea. The lambda object itself is still passed by value into the algorithm unless you wrap it. However, the lambda may already capture outside variables by reference.
This works because the copied lambda still holds a reference capture to count. That is often simpler than building a named functor just to share state.
Not Every Algorithm Treats State the Same Way
std::for_each is commonly used in these discussions because it returns the function object by value, which can preserve updated state if you store the return value. Many other algorithms do not do that, so std::ref is the more generally reliable tool when you need shared state across the call.
That makes the reference intent explicit.
It also improves readability for maintainers.
The call site explains the ownership choice.
Common Pitfalls
- Many algorithms copy the callable, so mutating state inside it may not affect the original object.
- '
std::refis the usual tool when the algorithm should act on the original functor.' - Returning functors from algorithms such as
std::for_eachcan preserve updated state, but that is algorithm-specific and easy to forget. - Reference passing is helpful for stateful callables, but unnecessary for small stateless predicates.
Summary
- Standard algorithms generally receive callables by value.
- Use
std::refwhen you need reference semantics for a function object. - Stateful functors are the main reason this matters.
- Lambdas with reference captures can sometimes solve the same problem more simply.
Related reading
- path compression is enough for disjoint-set forests , why do we need union by rank
- Path finding Algorithms A Vs Jump Point Search
- Pathfinding on large map
- Pathfinding routing, trip planning, ... algorithms on graphs with time restrictions
- Performance consequence of volatile member functions
- Performance impact of realloc
- paxos algorithm - how does the propose stage work?
- Paxos algorithm in the context of distributed database transaction

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.