为什么按副本捕获lambda具有相同的外部变量地址

时间:2017-05-19 22:17:38

标签: c++ c++11 lambda

我正在检查一些我用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中的地址,它们是相同的,不应该只有在被引用捕获时才会发生吗?可能我在这里遗漏了一些东西。

1 个答案:

答案 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.

我的建议:尽量避免使用默认捕获模式,因为有一天会出现意外或遗忘的行为。