6

我很难理解 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(); 
  }
};

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

A 1
A 1
B 1
B 2

所以我的问题是:

  1. 这是期望的行为吗?
  2. 如果我在 ClassA 中使用 [&] 而不是 [=],这些 lambda 表达式是否相同?
  3. 关于 [=] 何时实际复制是否有一些一般规则?
  4. 什么时候应该通过 lambdas 捕获变量?
  5. 我可以强制 lambda 重新捕获变量吗?

谢谢

4

1 回答 1

11

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

第二个捕获局部准变量this而不是成员变量x。所以body是等价的,并且会在你改变后printf("%d\n", this->x);打印新的值。2x

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

这是期望的行为吗?

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

如果我在 ClassA 中使用 [&] 而不是 [=],这些 lambda 表达式是否相同?

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

关于 [=] 何时实际复制是否有一些一般规则?

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

什么时候应该通过 lambdas 捕获变量?

创建 lambda 时。

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

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

于 2012-09-27T13:42:25.947 回答