Lambda capture by value

H. S. Teoh hsteoh at quickfur.ath.cx
Mon Feb 24 20:32:14 UTC 2020


On Mon, Feb 24, 2020 at 07:50:23PM +0000, JN via Digitalmars-d-learn wrote:
> import std.range;
> import std.stdio;
> 
> alias NumberPrinter = void delegate();
> 
> NumberPrinter[int] printers;
> 
> void main()
> {
>     foreach (i; iota(5))
>     {
>         printers[i] = () { write(i); };
>     }
> 
>     foreach (i; iota(5))
>     {
>         printers[i]();
>     }
> }
> 
> This prints 4 4 4 4 4.
> 
> How to make it so that it prints 0 1 2 3 4? Is it possible without
> changing the delegate definition to void delegate(int)?

The cause of the problem is that 'i' in the first foreach loop is
*reused* across loop iterations, so all 5 lambdas are actually closing
over the same variable, which gets its value replaced by the next
iteration.

To fix this, copy the value of 'i' to a local variable inside the loop
body, then the lambda will correctly capture a unique per-iteration
instance of the variable.  Like this:

    foreach (i; iota(5))
    {
	auto _i = i;
        printers[i] = () { write(_i); };
    }
 

T

-- 
Curiosity kills the cat. Moral: don't be the cat.


More information about the Digitalmars-d-learn mailing list