Step 5 of 6
Captures
The lambdas so far used only their own parameters. Often you need a value from outside the lambda, like a threshold the user typed in. A lambda can't see local variables automatically; you have to capture them in the []:
| Capture | Meaning |
|---|---|
[x] |
copy of x |
[&x] |
reference to x |
[=] |
copy everything used |
[&] |
reference everything used |
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
int main() {
std::vector<std::string> names = {"ana", "bartholomew", "cy", "delphine", "ed"};
size_t max_len = 3;
std::vector<std::string> shorts;
std::copy_if(names.begin(), names.end(), std::back_inserter(shorts),
[max_len](const std::string& s) { return s.size() <= max_len; });
for (const auto& s : shorts) std::cout << s << " ";
std::cout << "\n";
int letters = 0;
std::for_each(names.begin(), names.end(), [&letters](const std::string& s) { letters += (int)s.size(); });
std::cout << letters << " letters\n";
int bonus = 10;
auto add_bonus = [bonus](int x) { return x + bonus; };
bonus = 1000; // too late: the lambda holds its own copy
std::cout << add_bonus(5) << "\n";
}
ana cy ed
26 letters
15
Copy or reference?
[max_len]copies the value when the lambda is created. Later changes to the variable don't affect it, asadd_bonusshows.[&letters]refers to the real variable, so the lambda can change it. That's how the letter count builds up.- Capture by copy when you only read a small value; by reference when you need to update something, or to avoid copying something big.
back_inserter
std::copy_if(first, last, out, pred) copies the matching elements to out. Since you don't know in advance how many will match, you can't pre-size the result. std::back_inserter(v) (from <iterator>) is an output iterator that calls v.push_back(...) for every element written, so the vector grows as needed.
Common mistakes
- Using a variable in a lambda without capturing it: "error: 'threshold' is not captured".
- Capturing by reference in a lambda that outlives the variable, for example one stored and called after the function returned. The reference dangles.
Your turn: write std::vector<int> above(const std::vector<int>& v, int threshold) that returns the elements greater than threshold, keeping their order. Use std::copy_if with std::back_inserter(out) and a lambda that captures threshold.
Previous: accumulate and transform Next: Erase with a condition