5.2.22 · D5 · HinglishC++ Programming
Question bank — Lambda expressions — capture list (by value, by reference)
5.2.22 · D5· Coding › C++ Programming › Lambda expressions — capture list (by value, by reference)
True ya false — justify karo
Ek by-value capture [x] us waqt copy banata hai jab lambda invoke (call) hota hai.
False — copy us waqt hoti hai jab closure object construct hota hai (
[x] wali line run hoti hai), baad mein () se invoke karne par nahi. Construction (closure banana) aur invocation (operator() chalana) do alag events hain; snapshot construction par liya jaata hai, toh original mein baad ke changes dikhte nahi.[&x] ek baar x ka address copy karta hai, toh yeh x ki size chahe kuch bhi ho ek cheap fixed cost hai.
True — ek reference capture ek alias (address-sized) store karta hai, toh kisi bade object ko reference se capture karna utna hi cheap hai jitna kisi chhote object ko; sirf copy path size ke saath scale hota hai.
Ek hi by-value mutable lambda ko do baar call karne par dono baar same fresh copy se shuru hota hai.
False — copy lambda ka ek member hai jo calls ke beech persist karta hai;
[n]() mutable { n++; return n; } pehle 11 phir 12 return karta hai, kyunki internal n carry over hota hai.mutable add karne se lambda original captured variable ko change kar sakta hai.
False —
mutable sirf operator() se const hatata hai, jisse lambda ki apni copy mein editing allow hoti hai; bahar ki original variable ek alag object hai aur unchanged rehti hai.[=] aur [&] dono enclosing function mein declare ki gayi har local variable ko capture karte hain.
False — dono sirf woh variables capture karte hain jo body actually odr-uses karti hai (runtime par chahiye); jo variables tum kabhi mention nahi karte unka koi cost nahi aur woh store nahi hote.
By reference capture hamesha by value se zyada efficient hota hai.
False — trade-off dono taraf katta hai. Ek reference sirf ek address store karta hai, lekin har access par ek pointer indirection ka cost hota hai (real data tak pahunchne ke liye memory mein ek hop). Ek chhote POD (jaise
int) ki by-value copy essentially free hai banane mein aur phir in-register/inline rehti hai bina indirection ke, toh woh reference se actually zyada fast use ho sakti hai — reference-capture sirf tab clearly jeetata hai jab object bada ho aur uski copy expensive ho.Empty capture list [] wala lambda phir bhi ek plain function pointer mein convert ho sakta hai.
True — koi capture nahi toh koi state carry karne ki zaroorat nahi, toh closure ek free function ke equivalent hai aur function pointer mein convertible hai; koi bhi capture us conversion ko khatam kar deta hai.
Do lambdas jo identical text aur identical captures ke saath likhe gaye hain unka same type hota hai.
False — har lambda expression ek unique, unnamed closure type produce karta hai, toh textually identical lambdas bhi alag types hote hain (isliye tum inhe
auto ya std::function mein store karte ho).[x = expr] (C++14 init-capture) ke liye zaroorat hai ki x enclosing scope mein ek variable ke roop mein pehle se exist kare.
False — init-capture ek brand-new closure member
x banata hai jo expr se initialize hota hai; bahar ka koi variable named x hona zaroorat nahi, yahi wajah hai ki tum fresh state introduce karne ya moved value capture karne ke liye iska use karte ho.[*this] (C++17) aur [this] closure mein same cheez store karte hain.
False —
[this] pointer store karta hai (live object ka alias, danglable), jabki [*this] poore *this object ko closure mein copy karta hai, toh lambda ek independent snapshot ka malik hota hai jo original ke marne ke baad bhi survive karta hai.Error dhundho
auto f = [&x]() { return x; }; ek aise function se return ho rahi hai jahan x ek local hai — kya problem hai?
Yeh figure se "box ke bahar arrow" wala case hai: function return hone par
x mar jaata hai, toh stored reference dangle karta hai; baad mein f call karna dead stack memory padhta hai (UB). Closure ke andar copy live rahe isliye [x] by value capture karo.int n=10; auto c=[n](){ n++; return n; }; — yeh compile kyun nahi hoga?
operator() by default const hai, toh by-value member n read-only hai; n++ reject ho jaata hai. Internal copy ko edit karne ki permission dene ke liye mutable add karo.[=, x] — is capture list mein kya illegal hai?
Tum aise capture ko repeat nahi kar sakte jo default pehle se same mode mein cover karta hai;
[=] already x ko by value leta hai, toh x ko dobara by value name karna redundant/ill-formed hai. Sirf opposite mode as an exception ([=, &x]) allowed hai.[&, &x] — yeh kyun reject hota hai?
Default
& already sab kuch by reference capture karta hai, toh x ko dobara reference mein list karna duplicate hai; ek exception default se alag hona chahiye (jaise [&, x]).auto lam = [this]() { return value; }; ek container mein store ki gayi jo object se zyada survive karti hai — kya trap hai?
[this] raw this pointer capture karta hai (ek "arrow bahar"); agar enclosing object pehle destroy ho jaye, toh this bilkul reference ki tarah dangle karta hai. Dekho Object lifetime and scope — agar lambda escape kare toh [*this] (C++17, object in-copy karta hai) ya needed members ko by value capture karna prefer karo.auto f = [p]() { return *p; }; jahan p ek std::unique_ptr<int> hai — yeh compile kyun nahi hoga?
unique_ptr move-only hai (koi copy constructor nahi), aur [p] by-value copy maangta hai; compiler ise reject karta hai. Ownership closure mein transfer karne ke liye init-capture [p = std::move(p)] use karo.[&]-capturing lambda ko std::thread and async ke through thread mein pass karna, phir caller scope end hone dena — kya bug hai?
Thread local variables ke marne ke baad run kar sakta hai, toh references threads ke across dangle karte hain. By value capture karo (ya
unique_ptr ko [p = std::move(p)] se move in karo) taaki worker apna data caller ke stack se independent rakh sake.Why questions
Parent note kyun kehta hai ki lambda "secretly ek struct" hai?
Kyunki compiler actually ise ek anonymous class mein
operator() ke saath rewrite karta hai; captures member variables ban jaate hain. Yeh ek mental model value vs reference, const, aur mutable sab kuch ek saath explain karta hai — yeh ek hand-written functor jaisa hi hai.operator() by default const kyun hai, aur yeh by-value captures se kaise connect karta hai?
Ek
const call operator promise karta hai ki closure ki state mutate nahi hogi, jo const member functions ko mirror karta hai; yeh by-value members ko read-only banata hai, isliye kisi ek ko edit karne ke liye mutable chahiye.By reference "latest value dekhta hai" jabki by value "frozen snapshot dekhta hai" — aisa kyun?
Ek reference member original memory ka alias hai, toh har read us same location ko dereference karta hai jahan original rehta hai; ek value member creation par ek baar liya gaya independent copy hai, baad ke writes se disconnected.
Lambda store, return, ya async code ko dene par by value capture prefer kyun karein?
Kyunki lambda ki lifetime tab enclosing scope se zyada ho jaati hai; by value mein data closure ke andar rehta hai, toh kuch dangle nahi kar sakta. Yeh "sandwich carry karo, note mat chhodo" rule hai.
By value safer hone ke bawajood by-reference capture kab prefer kiya jaata hai?
Jab tum genuinely outside world ko mutate karna chahte ho (jaise ek running counter
++count) ya captured object bahut bada hai aur lambda clearly apne scope ke andar rehta hai, toh reference dono correct aur cheap hai.[&x] store karna [bigObject] se sasta kyun hai?
Ek reference address-sized hota hai chahe woh kisi bhi cheez ki taraf point kare (dekho References vs pointers in C++), jabki ek by-value capture poore object ko closure mein copy-construct karna padta hai, jo uski size ke saath scale karta hai.
[this] capture karna by-value se zyada by-reference ki tarah kyun behave karta hai?
Yeh current object ka pointer store karta hai, copy nahi; lambda phir iske through live members tak pahunchta hai, toh agar object mar jaye toh pointer dangle karta hai — reference-style lifetime hazard.
[*this] ise fix karta hai object ko andar copy karke.Init-capture [p = std::move(p)] language mein kyun add kiya gaya?
Pre-C++14 captures sirf ek existing variable ko copy ya reference kar sakte the, toh
std::unique_ptr jaise move-only types closure mein enter hi nahi kar sakte the; init-capture tumhe ek member ko move-construct karne deta hai, ownership lambda mein transfer karte hue.Edge cases
Ek lambda kuch bhi capture nahi karta aur sirf apne parameters use karta hai — capture list kaisi dikhti hai aur kyun?
Yeh
[] hoti hai; parameters call time par supply hote hain, enclosing scope se nahi, toh koi capture ki zaroorat nahi. Aisi lambdas hi function pointers mein convertible hoti hain.Kya hota hai agar ek by-value capture expensive copy wale type ka ho lekin tum sirf use read karo?
Tum creation par read-only use ke liye full copy pay karte ho; agar lambda scope mein rahe, toh by reference capture (ya
const reference intent) copy se bachata hai, lekin sirf tab jab lifetime safety guaranteed ho.Ek global (ya static) variable body mein use hota hai lekin [...] mein listed nahi — kya yeh error hai?
Nahi — globals aur statics local variables nahi hain, toh woh capture nahi hote; lambda simply unhe directly refer karta hai. Sirf enclosing local variables ko capturing ki zaroorat hoti hai.
[=] use hota hai lekin body ek aise variable ko read karti hai jo creation ke baad modify nahi hota — [&] se koi difference?
Padhi gayi value ke liye observably koi difference nahi, lekin
[=] copy karta hai (scope se survive karna safe hai) jabki [&] alias karta hai (escape hone par dangle karta hai); baad mein koi mutation nahi toh real distinction sirf lifetime safety aur copy cost hai.Ek mutable by-value lambda ek doosre variable mein copy ki jaati hai — kya woh internal counter share karte hain?
Nahi — lambda copy karne par uski member state copy hoti hai, toh har copy ka apna independent counter hota hai; ek ko increment karna doosre ko affect nahi karta.
Reference type ki variable ko by value capture karna — copy live hai ya frozen?
By-value capture closure creation par referent ki value ko copy karta hai, ek frozen snapshot deta hai; closure member ek plain value hai, khud reference nahi, toh original mein baad ke changes nahi dikhte.
[p = std::move(p)] se ek std::unique_ptr move in karne ke baad, bahar ke p ki state kya hai?
Moved-from bahar ka
p empty (null) reh jaata hai — ownership ab closure ke andar rehti hai; purane p se dereference karna ek bug hoga, aur sirf lambda object ki lifetime ka zimmedar hai.Kya ek lambda jo unique_ptr ko move se capture karta hai copy ki ja sakti hai?
Nahi — kyunki yeh ek move-only member hold karta hai, closure khud bhi move-only ban jaata hai; tum lambda ko move kar sakte ho lekin copy nahi (aur ise
std::function mein store nahi kiya ja sakta, jise copyability chahiye).[*this] ka [this] ke comparison mein kya cost hai, aur yeh kab worth it hai?
[*this] poore enclosing object ko closure mein copy karta hai (memory + copy cost), jabki [this] sirf ek pointer copy karta hai; copy tab worth it hai jab lambda object ki lifetime se escape kare (async work, stored callbacks) taaki woh dangle na kar sake.Recall Reasoning checklist — dono figures aur upar ke examples se tied
Ye teen questions Figure 1 (copy-inside vs arrow-out) aur Figure 2 (decision map) ke against walk karo:
- Copy/alias kab form hota hai? Hamesha construction par (
[...]wali line), invocation par kabhi nahi — yeh pehla true/false trap hai. - Kya lambda variable/object se zyada survive karta hai? Agar haan toh tum Figure 1 ke "arrow out" side par ho aur Figure 2 ke escaping branch par — value,
[*this], ya move-in ([p = std::move(p)]) use karo, bilkul jaisa return-a-lambda aur hand-to-thread errors mein hai. - Kya main original change karna chahta hun? Haan → reference (
++countexample). Sirf meri private copy →mutablevalue ([n]() mutable { n++; }example, jo bahar kenko kabhi nahi chhuta).