A lambda creates a callable object with an optional capture list. Capturing by value copies selected state into the closure; capturing by reference keeps access to the original object. The central safety question is whether every referenced object will still exist when the lambda runs.
An explicit threshold capture communicates the dependency and avoids accidentally retaining unrelated local state.
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
const std::vector<int> values{3, 12, 8, 20};
const int threshold = 10;
std::for_each(values.begin(), values.end(), [threshold](int value) {
if (value >= threshold) std::cout << value << '\n';
});
}
12
20
mutable permits modification of a value-captured copy, not the original variable. An auto parameter creates a generic lambda whose call operator is a template. Use both only when they clarify the local operation.
Use explicit captures for callbacks that outlive the current statement. A blanket [&] can leave dangling references when stored or executed asynchronously. Capturing this stores a pointer, not a copy of the object; use an ownership-aware strategy such as a weak_ptr when callback lifetime may exceed the owner.
mutable allows a value-captured copy to change inside the closure without changing the original. Generic lambdas use auto parameters and can express small local algorithms. Keep a lambda short enough that its captures and result remain obvious; promote substantial reusable behavior to a named function object or function.
A reference capture is safe only while the referenced object remains alive. When a callback escapes the creating scope, capture the required value, move an owned resource into the closure, or use a lifetime-aware smart pointer. Avoid broad default captures in long-lived callbacks because they hide what the closure owns.
Use mutable only when a value-captured closure intentionally maintains private state. That state belongs to the closure object and is not a write back to the original variable.
#include <iostream>
auto make_counter(int start) {
return [value = start]() mutable { return ++value; };
}
int main() {
auto counter = make_counter(4);
std::cout << counter() << ' ' << counter() << '\n';
}
5 6
The closure owns its captured value, so it remains valid after make_counter returns.
Try this next
0 of 2 completed
It becomes unsafe when the lambda outlives the captured local variable, such as after being stored for later execution.
It allows the lambda to modify its own copies of value-captured variables. The original variables remain unchanged.
They keep a small predicate or transformation next to the algorithm call without requiring a separate named function.
Explore 500+ free tutorials across 20+ languages and frameworks.