[capture](parameters) { body } defines an anonymous, inline function object. The capture clause is C++'s distinguishing feature here: [=] captures every used outer variable by value (a copy, taken at the moment the lambda is created), [&] captures by reference (accessing the actual outer variable, which can change later), and specific names like [x, &y] mix the two explicitly per-variable. This forces a deliberate choice most languages with implicit closures don't require — and getting it wrong, particularly capturing by reference a variable that goes out of scope before the lambda is called, produces a genuine dangling-reference bug.
Basic lambda syntax
[](int a, int b) is the capture clause (empty here — nothing from the outer scope is used) followed by the parameter list, just like an ordinary function.
auto add = [](int a, int b) { return a + b; };
std::cout << add(3, 4) << "\n"; // 7
std::vector<int> nums = {5, 2, 8, 1};
std::sort(nums.begin(), nums.end(), [](int a, int b) {
return a > b; // descending order — passed directly as the comparator
});[=] vs [&]: capture by copy or by reference
[=] captured threshold's VALUE at the moment the lambda was created — later changing threshold has no effect on the already-captured copy; [&] would instead see the live, current value each time the lambda runs.
int threshold = 10;
auto byValue = [=](int x) { return x > threshold; }; // COPIES threshold at creation time
auto byRef = [&](int x) { return x > threshold; }; // references the LIVE threshold
threshold = 100;
std::cout << byValue(50) << "\n"; // true — still using the OLD copy (threshold was 10)
std::cout << byRef(50) << "\n"; // false — sees the CURRENT threshold (100)The real danger: dangling references
badLambda captured x BY REFERENCE, but x no longer exists once makeLambda returns — calling badLambda() later reads memory that's already been reclaimed, genuine undefined behavior, not a hypothetical concern.
std::function<int()> makeLambda() {
int x = 42;
return [&]() { return x; }; // captures x BY REFERENCE — x is a LOCAL variable
} // x is destroyed here, when makeLambda returns
auto badLambda = makeLambda();
// badLambda(); // UNDEFINED BEHAVIOR — x no longer exists
// the fix: capture by VALUE instead, when the lambda might outlive the current scope
// return [=]() { return x; }; // this copy of x survives