5.2.22 · Coding › C++ Programming
Ek lambda ek function hai jo aap inline likh sakte ho — lekin iska asli superpower yeh hai ki yeh surrounding scope ke variables ko yaad rakh sakta hai. Capture list [...] ek contract hai jo batata hai ki kaun se baahri variables is chhoti function ko use karne ki permission hai, aur WO unhe KAISE leta hai : ek frozen snapshot (by value ) ya original se ek live wire (by reference ).
Definition Lambda expression
Ek lambda ek anonymous function object hai. Puri anatomy:
capture list [ capture ] like fn args ( params ) optional mutable optional → ret { body }
auto add = []( int a , int b ){ return a + b; }; // [] = captures nothing
add ( 2 , 3 ); // 5
[...] wala part. Isme enclosing scope ke local variables list hote hain jo lambda body use kar sakti hai.
[x] → x ko by value capture karo (ek copy lambda ke andar store hoti hai).
[&x] → x ko by reference capture karo (lambda address store karta hai; yeh original ko touch karta hai).
[=] → har cheez jo use ho , by value capture karo (default-capture-by-value).
[&] → har cheez jo use ho , by reference capture karo.
[=, &y] / [&, x] → ek default plus exceptions.
[this] → enclosing object ka this pointer capture karo.
Intuition Lambda secretly ek struct kyun hai
Compiler har lambda ko ek hidden class mein rewrite karta hai jisme operator() hota hai. Capture list us class ki member variables ban jaati hai. Yeh ek idea sab kuch explain kar deta hai value vs reference ke baare mein.
Ek lambda
int n = 10 ;
auto f = [ n ]( int x ){ return x + n; };
roughly aise compile hota hai:
struct __Lambda {
int n; // captured BY VALUE -> member ki tarah store hua (ek COPY)
int operator () ( int x ) const // const! isliye by-value default mein read-only hota hai
{ return x + n; }
};
__Lambda f{ n }; // n creation time par struct mein copy ho gaya
Ab by reference se compare karo:
auto g = [ & n ]( int x ){ return x + n; };
// struct { int& n; int operator()(int x) const { return x + n; } };
Member ek reference int& hai — original n ka alias. Toh g hamesha n ki current value dekhta hai.
Worked example 1. By value = snapshot
int n = 1 ;
auto f = [ n ]() { return n; }; // n=1 ABHI copy karo
n = 99 ; // original badlo
std ::cout << f (); // 1 print hoga
Yeh step kyun? Copy [n] line par bani thi jab n 1 tha. Baad mein n = 99 assign karna sirf baahri variable ko edit karta hai; lambda ki private copy untouched rehti hai.
Worked example 2. By reference = live link
int n = 1 ;
auto g = [ & n ]() { return n; }; // &n store karo
n = 99 ;
std ::cout << g (); // 99 print hoga
Yeh step kyun? [&n] address store karta hai. Jab g() run hota hai toh woh us memory mein abhi jo hai wo padhta hai — aur humne abhi wahan 99 likha hai.
mutable — by-value copy ko edit karna
int n = 10 ;
auto c = [ n ]() mutable { n ++ ; return n; }; // COPY ko edit karta hai
std ::cout << c (); // 11
std ::cout << c (); // 12 (copy calls ke beech persist karti hai)
std ::cout << n; // 10 (original kabhi nahi badla)
Yeh step kyun? Default mein operator() const hota hai, isliye by-value member ko modify nahi kar sakte. mutable const hata deta hai, jisse aap internal copy change kar sako. Original n ek alag object hai, isliye 10 hi rehta hai.
Worked example 4. Ek stateful counter (classic use)
int count = 0 ;
auto tick = [ & count ]() { ++ count; };
tick (); tick (); tick ();
std ::cout << count; // 3
Yeh step kyun? Hum chahte hain ki lambda baahri duniya ko affect kare (accumulate kare). By reference exactly wahi tool hai: yeh real count ko mutate karta hai.
Worked example 5. Defaults mix karna
int a = 1 , b = 2 ;
auto m = [ = , & b ]() mutable { a += 10 ; b += 10 ; return a + b; };
// a by value capture hua (copy), b by reference (live)
m (); // copy a=11, b becomes 12 -> 23 return karta hai
std ::cout << a; // 1 (copy edit hua, original nahi)
std ::cout << b; // 12 (original reference se edit hua)
Yeh step kyun? [=, &b] matlab "default by value, siwaaye b ke jo by reference hai." Toh a ek private copy hai; b asli cheez hai.
Common mistake "By reference hamesha better hai — copies avoid hoti hain."
Kyun sahi lagta hai: copying expensive hai, references free hain, toh reflexively [&] use karna efficient aur clean lagta hai.
Kyun dangerous hai: agar lambda captured variable se zyada jiye , toh reference dangle karta hai → undefined behavior .
auto make () {
int x = 42 ;
return [ & x ]() { return x; }; // BUG: x tab mar jaata hai jab make() return karta hai!
}
auto bad = make ();
bad (); // dead memory padhna — UB
Fix: jab lambda scope se escape kare (store ho, return ho, async/threads ko pass ho) toh by value capture karo. [x] (ya [=]) use karo taaki value lambda ke andar jiye.
Common mistake "By-value captures lambda ke andar modify ki ja sakti hain."
Kyun sahi lagta hai: x body mein named hai, toh zaroor change kar sakte hain.
Fix: operator() default mein const hai → by-value members read-only hain. Copy ko modify karne ke liye mutable add karo (jo original ko tab bhi touch nahi karta).
[=] function ke har local variable ko capture karta hai."
Kyun sahi lagta hai: = lagta hai "sab kuch le lo."
Fix: default captures sirf wahi variables capture karta hai jo lambda body actually use karti hai (odr-uses). Unused wale kuch nahi lete.
Mnemonic Capture mode yaad rakhne ka tarika
"Value = ek photo, Reference = ek phone line."
Ek photo moment ko freeze kar deti hai (snapshot, door le jaana safe). Ek phone line live insaan ko ring karti hai (current value, lekin agar woh chale gaye → dangling).
Recall Feynman: ek 12-saal ke bacche ko explain karo
Soch lo tum ek lunchbox (lambda) pack kar rahe ho baad mein use karne ke liye. Tum ya toh asli sandwich andar rakh sakte ho (by value) — woh tumhara hai, fully portable, lekin woh sandwich waisi hai jaise pack karte waqt thi. Ya tum ek note chipka sakte ho jisme likha ho "Mom se kitchen mein sandwich maango" (by reference) — tumhe hamesha taaza milega, lekin agar Mom vacation par chali gayi (variable ka scope khatam hua), toh tumhara note ek khaali kitchen ko point karta hai aur tumhe kuch nahi milta (crash). Toh: saath le jaana hai → asli cheez rakh do (value). Kitchen ke paas raho aur taaza chahiye → note rakh lo (reference).
Compiler ek lambda ko secretly kya bana deta hai?
By-value capture mutable ke bina read-only kyun hoti hai?
Kab [&] use karna ZAROOR avoid karna chahiye?
[=, &b] ka matlab kya hai?
Lambda ki capture list [...] kya specify karti hai? Enclosing-scope ke kaun se local variables lambda use kar sakta hai, aur kaise (by value=copy, ya by reference=alias).
By value [x] vs by reference [&x]: original mein baad ke changes kaun dekhta hai? By reference [&x] current (live) value dekhta hai; by value [x] creation time ka frozen snapshot rakhta hai.
Lambda compile hokar kya banta hai? Ek anonymous class (closure type) jisme operator() hoti hai; captures uski member variables ban jaate hain.
Default mein lambda ke andar by-value captured variable ko modify kyun nahi kar sakte? Kyunki operator() default mein const hoti hai; captured copy ek const member hai. Copy ko edit karne ke liye mutable use karo.
Kya by-value capture ko mutable se edit karna original variable ko change karta hai? Nahi — sirf lambda ki internal copy change hoti hai; original untouched rehta hai.
[=] kya capture karta hai?Jo kuch body actually use karti hai, by value (copies).
[&] kya capture karta hai?Jo kuch body actually use karti hai, by reference (aliases).
[=, &y] ka matlab kya hai?Default capture by value, lekin y specifically by reference.
By reference capture karne ka main khatre kya hai? Dangling reference / UB agar lambda captured variable ke scope se zyada jiye (e.g., return ho, store ho, async use ho).
Jab lambda apna scope escape kare, kaunsa capture prefer karna chahiye? By value, taaki data lambda ki apni storage mein jiye.
[this] kya capture karta hai?Enclosing object ka this pointer, jisse lambda uske members access kar sake.
Function objects (functors) — ek lambda hai ek compiler-generated functor.
std::function — type-erased wrapper jo kisi bhi lambda ko hold kar sakta hai.
References vs pointers in C++ — [&x] ke peeche int& member ko explain karta hai.
Object lifetime and scope — dangling-reference trap ki jad.
const member functions — kyun by-value captures default mein read-only hain.
std::thread and async — classic jagah jahan by-reference capture galat ho jaata hai.
Hidden struct with operator
Member variables of struct
By value read-only by default