lambda capture by value (tsz. lambda capture by values)
Egy lambda formális szintaxisa:
(parameter_list) -> return_type { body }
Ebben a szintaxisban a capture
rész az ún. capture list vagy befogási lista. Ez határozza meg, hogy a lambda milyen külső változókat (amelyek a lambda definíciós helyén léteznek) “visz magával” a belsejébe, és hogyan.
Két alapvető mód van erre:
by value
) → másolatot készítby reference
) → hivatkozást visz magávalMost az érték szerinti befogást fogjuk részletesen vizsgálni.
Amikor érték szerint fogsz be egy változót, akkor a lambda másolatot készít az aktuális értékéről abban a pillanatban, amikor a lambdát létrehozod.
Ez azt jelenti, hogy:
const
lesz)Szintaxis:
// csak az 'x' változót fogjuk be érték szerint
// minden külső változót érték szerint fogunk be
#include <iostream>
int main() {
int x = 10;
auto lambda = () {
std::cout << "x inside lambda: " << x << std::endl;
};
x = 20;
lambda(); // Mi lesz az eredmény?
}
Kimenet:
x inside lambda: 10
Magyarázat:
azt jelenti, hogy a lambda 10-es értékkel másolta be az x
-et, amikor a lambdát létrehoztuk.x = 20;
módosítás a lambdán belül nem fog látszani, mert az a lambda példányába másolatként bekerült x
-re nincs hatással.
A szintaxis azt jelenti, hogy minden használt külső változót érték szerint fogunk be:
#include <iostream>
int main() {
int x = 5;
int y = 8;
auto lambda = () {
std::cout << "x: " << x << ", y: " << y << std::endl;
};
x = 100;
y = 200;
lambda();
}
Kimenet:
x: 5, y: 8
Miért? A lambda létrehozásakor x
és y
aktuális értékei kerültek másolatként a lambda példányába. A későbbi módosítás nem látszik.
Alapértelmezetten nem – mert a lambda belsejében a befogott érték const lesz.
Példa:
#include <iostream>
int main() {
int x = 5;
auto lambda = () {
x = 10; // HIBA! x const
};
lambda();
}
Fordítási hiba: x
const.
Ha azt szeretnéd, hogy a lambda belsejében az érték szerinti befogott változó módosítható legyen, használhatod a mutable
kulcsszót:
#include <iostream>
int main() {
int x = 5;
auto lambda = () mutable {
x = 10;
std::cout << "x in lambda: " << x << std::endl;
};
lambda();
std::cout << "x outside: " << x << std::endl;
}
Kimenet:
x in lambda: 10 x outside: 5
Mi történik?
x
-ről.mutable
engedélyezi, hogy ezt a másolatot a lambda belsejében módosítsuk.x
a lambda kívül nem változott meg.
Ha egy lokális változót akarsz befogni, capture by value védi meg a lambdát a dangling reference hibától.
Példa:
#include <iostream>
#include <functional>
std::function<void()> makeLambda() {
int x = 42;
return () {
std::cout << "x: " << x << std::endl;
};
}
int main() {
auto lambda = makeLambda();
lambda(); // x még él, mert by value volt befogva!
}
Ha itt &x
-el (referenciával) fogtuk volna be, a makeLambda()
után x
megszűnne → dangling reference.
C++14-től kezdve capture listában lehet move-olni is változót:
auto ptr = std::make_unique<int>(42);
auto lambda = () {
std::cout << "p: " << *p << std::endl;
};
Itt p
a lambda belsejébe move-olódik, így nem kell shared_ptr
-t használnod, ha az ownership a lambdához kerül.
✅ Stabil → nem változik, ha a külső változó módosul ✅ Biztonságos → nem lógó referencia ✅ Thread-safe → saját példány ✅ Egyszerű → formában tömeges capture
⚠️ Másolási költség → ha nagy objektumot fogsz be, költséges lehet ⚠️ Alapértelmezésben nem módosítható (mutable
kell hozzá)
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> v{1, 2, 3, 4, 5};
int factor = 2;
std::for_each(v.begin(), v.end(), (int x) {
std::cout << x * factor << " ";
});
std::cout << std::endl;
}
Kimenet:
2 4 6 8 10
Itt factor
érték szerint van befogva → biztosak lehetünk benne, hogy a for_each
ciklus közben a factor
értéke nem változik.
A capture by value a lambda egyik leghasznosabb eszköze:
mutable
segítségével belső állapotkezelést is lehet vele csinálni.Fontos figyelembe venni:
by value
by reference