lambda的捕获机制

use*_*208 6 c++ lambda

我无法理解lambda函数和捕获变量的机制,因此我做了一些测试并得出了非常奇怪的结论.那是:

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(); 
  }
};
Run Code Online (Sandbox Code Playgroud)

注意:唯一的区别在于x变量的位置; ClassA和ClassB的功能有不同的输出!

A 1
A 1
B 1
B 2
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:

  1. 这是理想的行为吗?
  2. 如果我在ClassA中使用[&]而不是[=],那些lambdas是否相同?
  3. 是否有一些关于何时[=]实际制作副本的一般规则?
  4. 究竟是什么时候应该发生lambda的变量捕获?
  5. 我可以强制lambda重新捕获变量吗?

谢谢

Mik*_*our 11

第一个x按值捕获局部变量; 所以它打印1两次,因为它的副本没有改变.

第二个捕获本地准变量this,而不是成员变量x.所以身体是等同的printf("%d\n", this->x);,并且会2在你改变之后打印出新的价值x.

如果您要明确捕获x(即[x](){...}),那么您将看到与第一个相同的结果.

这是理想的行为吗?

这是语言标准指定的行为.

如果我在ClassA中使用[&]而不是[=],那些lambdas是否相同?

不,但两者都会产生相同的输出.第一个将x通过引用捕获本地,因此您将看到对它的更改.

是否有一些关于何时[=]实际制作副本的一般规则?

是的,它在创建lambda时复制变量.

究竟是什么时候应该发生lambda的变量捕获?

当lambda被创建时.

我可以强制lambda重新捕获变量吗?

不会.一旦它被值捕获,它就有自己的变量副本,无法访问原始变量.如果您需要查看原始更改,请通过引用捕获(并注意对象生存期).