我无法理解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
所以我的问题是:
由于
答案 0 :(得分:11)
第一个按值捕获局部变量x
;所以它会两次打印1
,因为它的副本没有改变。
第二个捕获局部准变量this
,不成员变量x
。因此,正文与printf("%d\n", this->x);
相同,并且在您更改2
后会打印x
的新值。
如果您要明确捕获x
(即[x](){...}
),那么您将看到与第一个相同的结果。
这是理想的行为吗?
这是语言标准指定的行为。
如果我在ClassA中使用[&amp;]而不是[=],那些lambdas是否相同?
不,但两者都会产生相同的输出。第一个将通过引用捕获本地x
,因此您将看到对它的更改。
是否有一些关于何时[=]实际制作副本的一般规则?
是的,它在创建lambda时复制变量。
究竟是什么时候应该发生lambdas对变量的捕获?
创建lambda时。
我可以强制lambda重新捕获变量吗?
没有。一旦它被值捕获,它就有自己的变量副本,无法访问原始变量。如果您需要查看原始更改,请通过引用捕获(并注意对象生存期)。