5.2.22 · D4 · HinglishC++ Programming

ExercisesLambda expressions — capture list (by value, by reference)

2,472 words11 min read↑ Read in English

5.2.22 · D4 · Coding › C++ Programming › Lambda expressions — capture list (by value, by reference)

Yeh page parent topic Lambda expressions — capture list (by value, by reference) ko revisit karta hai aur prerequisites References vs pointers in C++, Object lifetime and scope, Function objects (functors), std::function, const member functions, aur std::thread and async pe lean karta hai.


Level 1 — Recognition

Goal: capture list padho aur batao ki uska MATLAB kya hai, execution ki zaroorat nahi.

Recall Solution 1.1
  • [a]a by value.
  • [&a]a by reference.
  • [=] → sab used (a,b,c) by value.
  • [&] → sab used (a,b,c) by reference.
  • [=, &b] → default by value (a,c copies), lekin b by reference.
  • [&, a] → default by reference (b,c aliases), lekin a by value.

Kyun: leading = ya & default set karta hai; uske baad har explicit entry exception hoti hai.

Recall Solution 1.2
  • p mein [n] hai → photo (n = 5 ka frozen snapshot).
  • q mein [&n] hai → phone line (real n tak live wire).

Level 2 — Application

Goal: ek single lambda apne dimaag mein execute karo aur printed number do.

Recall Solution 2.1 — prints

1 Copy [n] wali line pe hua jab n == 1 tha. Struct ki tarah rewrite karne pe, member int n ko 1 se initialise kiya gaya tha. Baad mein n = 99 sirf bahari variable ko edit karta hai. Answer: 1.

Recall Solution 2.2 — prints

99 Member int& n hai (real n ka alias). Call time pe yeh current value dereference karta hai, jo 99 hai. Answer: 99.

Recall Solution 2.3 — A=

11, B=12, C=10 mutable operator() se const hata deta hai, isliye internal copy member (start 10) change ho sakta hai. Call 1: 10→11, returns 11. Call 2: 11→12, returns 12 — copy calls ke beech persist karti hai kyunki yeh lambda object ke andar rehti hai. Original n ek alag object hai, abhi bhi 10. A=11, B=12, C=10.


Level 3 — Analysis

Goal: do captures, mixed defaults, aur side effects ke across reason karo.

Recall Solution 3.1 — r=

23, a=1, b=12 [=, &b]: a ek copy member hai, b ek reference member hai. m() ke andar: copy-a 1→11 jaata hai; real-b 2→12 jaata hai. Returns 11 + 12 = 23. Bahar: original a unchanged (1), original b reference ke zariye edit hua (12). r=23, a=1, b=12.

Recall Solution 3.2 — prints

5 20 byVal ne creation pe 5 freeze kar liya. byRef live x ko alias karta hai, jo ab 20 hai. Output: 5 20.

Recall Solution 3.3 — prints

2 Dono lambdas same count ko alias karte hain. Teen ++ phir ek --: 0 → 3 → 2. Dono ek hi insaan ke phone line hain. Answer: 2.


Level 4 — Synthesis

Goal: capture rules ko lifetime aur closure identity ke saath combine karo.

Recall Solution 4.1 —

Undefined behaviour (dangling reference) x make() ka local hai. Jab make() return karta hai, x ki storage destroy ho jaati hai (dekho Object lifetime and scope). Return hua closure abhi bhi &x hold karta hai — ek dangling reference. bad() call karna dead memory padhta hai → UB (shayad 42, garbage, ya crash print kare). Fix: value by capture karo taaki value returned closure ke andar rahe. [&x][x] change karo (& delete karo, ek character fix). Phir closure apni copy 42 carry karega aur return karna safe hoga.

Recall Solution 4.2 — by value prints

012; by reference is UB By value [i]: har iteration current i (0, phir 1, phir 2) ko uss iteration ke closure mein copy karta hai. Output 0 1 2 → printed 012. By reference [&i]: har closure same loop variable i ko alias karta hai. Lekin i for ke scope mein hai; loop ke baad yeh out of scope hai → teeno references dangle karte hain → UB. (Marne se pehle bhi, teeno same final value padhte, 0/1/2 nahi.) Yahi reason hai ki closures store karte waqt [i] (value) prefer karte hain.

Recall Solution 4.3 — prints

100; hazard: dangling this [this] pointer to w store karta hai (poore object ka phone line). id uss pointer ke zariye padha jaata hai, isliye call time pe yeh current w.id == 100 dekhta hai. Prints 100. Hazard: closure w ko kahin bhi alive nahi rakhta — yeh sirf this borrow karta hai. Agar w g() run hone se pehle destroy ho jaata hai (jaise w ek temporary tha ya scope se bahar chala gaya), toh g() ek dead object dereference karta hai → UB. (C++17+ [*this] poora object copy karta hai isse avoid karne ke liye.)


Level 5 — Mastery

Goal: ek program ka full trace jo value, reference, mutable, aur shared state mix karta hai.

Recall Solution 5.1 — r1=

101, r2=103, r3=106, hits=3 Members: copy base (100 se shuru, mutable ki wajah se persist karta hai), reference hits (real hits ko alias karta hai).

  • Call 1: hits 0→1; copy-base 100→101; returns 101.
  • Call 2: hits 1→2; copy-base 101→103; returns 103.
  • Line Z: base = 0 original base ko edit karta hai — lekin lambda ke paas ek alag copy hai, isliye uska base abhi bhi 103 hai. Closure pe koi effect nahi.
  • Call 3: hits 2→3; copy-base 103→106; returns 106.
  • Final hits: reference ke zariye teen baar mutated 0 se → 3. r1=101, r2=103, r3=106, hits=3.
Recall Solution 5.2
struct __Closure {
    int  base;          // BY VALUE  -> its own copy
    int& hits;          // BY REFERENCE -> alias to outside hits
    int operator()() {  // 'mutable' -> NOT const, so 'base' is writable
        ++hits;
        base += hits;
        return base;
    }
};
__Closure make{ base, hits };   // base copied, hits aliased

Line Z ka koi effect kyun nahi hua: member int base ek distinct object hai jo construction ke waqt ek baar initialise hota hai; bahar ke base ko assign karna is alag member ko kabhi touch nahi karta — dekho Function objects (functors) struct-with-operator() view ke liye.


Wrap-up figures

Value-vs-reference divide ek picture hai: ek copy closure box ke andar baithti hai versus ek arrow jo original ki taraf bahar point karta hai.

Figure — Lambda expressions — capture list (by value, by reference)

Aur dangling trap (Exercises 4.1 / 4.2) ek timeline hai: reference uss cheez se zyada jee jaata hai jise woh point karta hai.

Figure — Lambda expressions — capture list (by value, by reference)

Recall Ek-line summary

Har lambda ko struct ki tarah rewrite karo: [x] → copy member (frozen, edit karne ke liye mutable chahiye, escape karna safe hai); [&x] → reference member (live, shared, dangle karta hai agar yeh apne variable ki lifetime se escape kare).