Passing function objects into std algorithms by reference
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
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.

