Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why capture lambda does not working in c++?

I am playing with lambda expressions in C++, and I have tried a few things to see the outcome. I actually watched the video in CppCon Back to Basics: Lambdas from Scratch - Arthur O'Dwyer - CppCon 2019 @21:47 and started to play with lambdas.

As an example, I've tried this:

#include <iostream>
using namespace std;
int g = 10;//global var 'g'

//creating lambda
auto kitten = [=] () {return g+1;};
auto cat = [g=g] () {return g+1;};
// main
int main()
{
    g = 20;//modifying global variable 'g'
    cout<<"kitten: "<<kitten()<<"cat: "<<cat()<<endl;

    return 0;
}

Output of the above code is:

kitten: 21cat: 11

In the above example: [g=g] means capture a data member whose name is g and whose type is the same as the outer g, as if I had written auto g=g. It's a copy of g. Which makes sense when we think that (as if I had written in the form of auto g=g) so the result is 11 in our case, where modification of the global g is not reflected in our local g.

The result for the kitten is 21 because as far as I understand, capture everything i.e., capture all external variable by value.

Then, when it comes to this example by modifying the first lambda as follows:

auto kitten = [] () {int g  = g; return g+1;};

Where I declared local g and assigned value from global g, the output is:

kitten: 1cat: 11

But I was expecting the output as in the first example (21) because I am trying the create a local g and assigning its value from the global g, where it is already the modified value of 20.

Codes are compiled on https://techiedelight.com/compiler/ and godbolt.org with c++ (GCC 8.3.0) (with the latest compiler, [=] this is not allowed, but the results are the same).

At this moment, I am a little confused about the concept of capturing and/or lambda.

like image 408
asevindik Avatar asked Aug 03 '26 20:08

asevindik


1 Answers

auto kitten = [=] () {return g+1;}

This lambda doesn't capture anything at all. It's nearly the same as just

int kitten() { return g+1; }

Only local variables can be captured, and there are no local variables visible in the scope of the kitten definition. Note that [=] or [&] don't mean "capture everything", they mean "capture anything necessary", and a global variable is never necessary (or possible) to capture in a lambda, since the meaning of that variable name is always the same no matter when the lambda body is evaluated.


auto cat = [g=g] () {return g+1;}

Here's an init-capture, which is similar to creating a local variable and immediately capturing it. The g before the equal sign declares the init-capture, and the g after the equal sign specifies how to initialize it. Unlike most declarators (see below), the g variable created here is not in scope in its own initializer, so the g after the equal sign means the global variable ::g. So the code is similar to:

auto make_cat()
{
    int & g = ::g;
    return [g]() { return g+1; }
}
auto cat = make_cat();

auto kitten = [] () {int g  = g; return g+1;}

This code has a mistake not really related to lambdas. In the local variable definition int g = g;, the declared variable before the equal sign is in scope during the initializer after the equal sign. So g is initialized with its own indeterminate value. Adding one to that indeterminate value is undefined behavior, so the result is not predictable.

like image 159
aschepler Avatar answered Aug 06 '26 12:08

aschepler



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!