I have a very simple recursive lambda which calculates sum of given 2 numbers:
auto sum_v1 = [](auto first){
return [first](auto second){
return first + second;
};
};
sum_v1 (1)(2); // returns 3, OK
Now the same function, using capture by reference for arg first.
auto sum_v2 = [](auto first){
return [&first](auto second){
return first + second;
};
};
sum_v2 (1)(2); // returns 4, NOT OK
sum_v2
gets the argument first
as 2
and arg second
is also 2
.
I know how to get the right result. I could use either the sum_v1 OR sum_v3 (shown below).
// accept arg first using r-value reference
auto sum_v3 = [](auto&& first){
return [first](auto second){
return first + second;
};
};
sum_v3 (1)(2); // returns 3, OK
How is sum_v2
, while creating the lambda, is seeing the arg first
as 2. I am struggling to understand that.
Could you please give me some hint(s) to understand this better? I am using gcc.9.2.0 with -std=c++17 on rhel 7.
Thanks, Gaurav
This:
auto sum_v2 = [](auto first){
return [&first](auto second){
return first + second;
};
};
Is undefined behavior, as you are taking a reference to a local variable first
whose lifetime ends before it is used. As with all UB, anything could happen. On your machine it seems that first
ends up referencing second
instead, but that's not guaranteed. The code could crash on other systems, or produce the expected result, but you can't rely on it.
With -Wall -Werror
you wouldn't even be able to compile this bad code. Demo: https://godbolt.org/z/3gYx7q