我正在检查一些我用lambda尝试的旧代码,我注意到了。 如果我将lambda capture指定为副本并修改其中的值,它将修改变量,因为它是一个引用。
void classV::setLambda() {
r.setLambda([=]() {
value = 100;
v = 10;
std::cout << &value << std::endl;
});
}
void classV::executeLambda() {
r.runLambda();
std::cout << "NVAL: " << value << std::endl;
std::cout << "NVAL: " << v << std::endl;
std::cout << &value << std::endl;
}
基本上,这段代码将lambda存储在外部对象(类实例)上并在那里执行,我想,将捕获指定为副本,当我试图获取那些变量的值时,那些不应该改变。 ..因为它被复制了。
但是,情况并非如此,值和v都是100和10。 具体来说,value是类classV的静态int,v是classV的int对象属性。
为什么这些值会被更改?,我检查了lambda和executeLambda中的地址,它们是相同的,不应该只有在被引用捕获时才会发生吗?可能我在这里遗漏了一些东西。
答案 0 :(得分:3)
[=]
会按值复制,并且您希望本地value
拥有不同的地址。
但是,C ++会对成员变量进行例外处理。它们仍然可以通过this
访问。所以你的代码等同于写作:
r.setLambda([=]() {
this->value = 100;
this->v = 10;
std::cout << &(this->value) << std::endl;
});
并且this
是一个指针,因此它与按值复制保持一致。
解决方案是写
r.setLambda([=,value]()
但您无法捕获成员变量。
您必须写:
auto valueCopy = value;
r.setLambda([=]()
// ... use valueCopy here.
我的建议:尽量避免使用默认捕获模式,因为有一天会出现意外或遗忘的行为。