Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda in for loop - static variable

Tags:

c++

c++11

lambda

Dear stackoverflow community!

Recently, I was hunting for a bug at work, which led me to the following piece of code I wrote myself. Here is a simplified version:

int main()
{
    for(int i = 0; i < 5; ++i)
    {
        int j = i + 1;

        auto k = [j](){
            static int s{j};
            cout << s << endl;
        };
        k();
    }
}

I know that it might look silly, but there was some logic behind it (since I was using this lambda to connect to a slot in QT framework)

Here are my expectations:

  1. each iteration of the loop new class with a functor operator will be created (since every time it captures new local variable)
  2. initialization of static variable s will happen once every iteration since it is a different lambda

However, I was wrong. After compiling with GCC 9.3.0 I got the following output:

1
1
1
1
1

Does it mean that 1 "hidden" functor is created once for every iteration of the loop (then a static is initialized during the first iteration of the loop)? Does it then mean that we should avoid nasty non-constexpr static variables in lambdas? Where am I wrong?

Thanks for you time, looking forward to any replies.

like image 879
Yurii A Avatar asked Nov 12 '20 10:11

Yurii A


People also ask

Can we use static variable in for loop?

Whenever the function is called, count will have the last value assigned to it. You can also use static in this fashion to prevent a variable from being reinitialized inside a loop.

Can Lambda be static?

A lambda or anonymous method may have a static modifier. The static modifier indicates that the lambda or anonymous method is a static anonymous function. A static anonymous function cannot capture state from the enclosing scope.


1 Answers

Think of a lambda expression as a terse recipe to define a class that overloads the call operator(). In your case:

struct LambdaEquivalent {
    int j;

    auto operator() const
    {
        static int s{j};
        cout << s << endl;
    }
};

And you loop then is

for(int i = 0; i < 5; ++i)
{
        int j = i + 1;
        LambdaEquivalent k{j};
        k()
}

This illustrates that any local static data in the body of a lambda expression is nothing but local static data in a member function - and that is initialized exactly once. It's a good thing that both cases behave identically, handling it differently could be very confusing.

like image 147
lubgr Avatar answered Oct 11 '22 07:10

lubgr