Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is 'this' captured in a lambda?

Tags:

I have a function in a class that defines a lambda and stores it in a local static variable:

class A { public:     void call_print()     {         static auto const print_func = [this] {             print();         };          print_func();     };      virtual void print()     {         std::cout << "A::print()\n";     } };  class B : public A { public:     virtual void print() override     {         std::cout << "B::print()\n";     } }; 

I also execute the following test:

int main() {     A a;     B b;      a.call_print();     b.call_print(); } 

(Live Sample)

What I expect to be printed is:

A::print() B::print() 

But what I really get is:

A::print() A::print() 

(Same object address is also printed with each)

I suspect this is due to the this capture. I assumed that it would capture the value of this when it is called, however it seems to be captured the moment the lambda is defined.

Could someone explain the semantics of lambda captures? When do they actually get provided to the function? Is it the same for all capture types, or is this a special case? Removing static fixes the problem, however in my production code I'm actually storing the lambda in a slightly-heavier object which represents a slot to which I insert into a signal later.

like image 559
void.pointer Avatar asked Jul 13 '16 14:07

void.pointer


People also ask

What does it mean to lambda capture this?

The lambda is capturing an outside variable. A lambda is a syntax for creating a class. Capturing a variable means that variable is passed to the constructor for that class. A lambda can specify whether it's passed by reference or by value.

What is capture clause in lambda function in C++?

A capture clause of lambda definition is used to specify which variables are captured and whether they are captured by reference or by value. An empty capture closure [ ], indicates that no variables are used by lambda which means it can only access variables that are local to it.

Does lambda capture reference by value?

Lambdas always capture objects, and they can do so by value or by reference.

What does [=] mean in lambda function?

The [=] you're referring to is part of the capture list for the lambda expression. This tells C++ that the code inside the lambda expression is initialized so that the lambda gets a copy of all the local variables it uses when it's created.


1 Answers

This has nothing to do with the semantics of lambda capture. It's simply how static works.

A static function-scoped variable is initialized exactly once. There is only ever one such object in your entire program. It will be initialized the first time the function is called (more specifically, the first time the static statement is executed). And therefore, the expression used to initialize the static variable is only ever invoked once.

So if a static function-scoped variable is initialized with data that's based on one of the function's parameters (like this), then it will only get the parameters from the first invocation of that function.

Your code creates a single lambda. It does not create different lambdas on each invocation of the function.

The behavior you seem to want is not a function-local static variable, but an object member. So just put a std::function object in the class itself, and have call_print initialize it if it is empty.

like image 190
Nicol Bolas Avatar answered Sep 18 '22 00:09

Nicol Bolas