user1316208
user1316208

Reputation: 687

lambda's capture mechanism

I have trouble understanding lambda functions and the mechanism to capture variables, so I did a little testing and arrived at really weird conclusion. that is:

class ClassA
{
public:
  std::function<void()> lambda;
  void DoYourStuff()
  {
    int x;
    x = 1;
    lambda = [=] () { printf("A %d\n", x);};
    lambda();
    x = 2;
    lambda(); 
  }
};

class ClassB
{
public:
  std::function<void()> lambda;
  int x;
  void DoYourStuff()
  {
    x = 1;
    lambda = [=] () { printf("B %d\n", x);};
    lambda();
    x = 2;
    lambda(); 
  }
};

Note: only difference is in placement of x variable; ClassA and ClassB's functions have different output!

A 1
A 1
B 1
B 2

So my questions are:

  1. Is this the desired behaviour?
  2. if i used [&] instead of [=] in ClassA, would those lambdas be identical?
  3. Is there some general rule as to when [=] actually makes copy?
  4. When exactly is the capturing of variables by lambdas supposed to happen?
  5. Can I force lambda to do a re-capture of variables?

Thanks

Upvotes: 6

Views: 289

Answers (1)

Mike Seymour
Mike Seymour

Reputation: 254751

The first captures the local variable x by value; so it prints 1 both times, since its copy hasn't changed.

The second captures the local quasi-variable this, not the member variable x. So the body is equivialent to printf("%d\n", this->x);, and will print the new value of 2 after you change x.

If you were to explicitly capture x (i.e. [x](){...}), then you will see the same result as the first.

Is this the desired behaviour?

It's the behaviour specified by the language standard.

if i used [&] instead of [=] in ClassA, would those lambdas be identical?

No, but both would produce the same output. The first would capture the local x by reference, so you will see the change to it.

Is there some general rule as to when [=] actually makes copy?

Yes, it copies the variable when the lambda is created.

When exactly is the capturing of variables by lambdas supposed to happen?

When the lambda is created.

Can I force lambda to do a re-capture of variables?

No. Once it's captured by value, it has its own copy of the variable, with no way to access the original. If you need to see changes to the original, then capture by reference (and take care with object lifetimes).

Upvotes: 11

Related Questions