【问题标题】:Why lambda capture by copy have the same address of an external variable为什么通过复制捕获的lambda具有相同的外部变量地址
【发布时间】:2017-10-20 03:45:12
【问题描述】:

我正在检查一些我用 lambda 尝试过的旧代码,我注意到了。 如果我将 lambda 捕获指定为副本并修改其中的值,它将修改变量,因为它是一个引用。

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 并在那里执行,我想象,当我试图获取那些不应该改变的变量的值时,将捕获指定为副本。 .. 因为它被复制了。

但是,事实并非如此,value 和 v 都是 100 和 10。 具体来说,value是classV的静态int,v是classV的int对象属性。

为什么要更改这些值?,我检查了 lambda 和 executeLambda 中的地址,它们是相同的,难道只有通过引用捕获它才会发生吗?可能我在这里遗漏了一些东西。

【问题讨论】:

  • 根据cppreference,“[=] 捕获通过复制当前的lambda主体中使用的所有自动变量引用对象如果存在”。
  • 我不太确定 cppreference 在技术上是否正确,或者在技术上 this 指针是否被复制捕获,但无论哪种方式,它都不应该复制您的实例变量或静态变量。
  • 一个 lambda 可以捕获局部变量(按值或按引用)和/或 this(总是按值,但它没有任何区别,因为无论如何都不能分配 this) .在[=, &amp;i] 的示例中,i 实际上是一个局部变量(一个函数参数)。在您的示例中,vvalue 不是局部变量;它们要么是classV 的成员(通过捕获的this 访问),要么是全局变量(您没有显示足够的代码来确定哪个)。
  • 这个问题很有意思,能不能发个完整的运行代码让我们试试?
  • 您似乎在询问有关您未显示的代码的问题。在您显示的代码中,没有名称冲突(有未声明的标识符,但没有多次声明的标识符)。如果您需要有关特定场景的帮助,请显示演示该场景的代码。

标签: c++ c++11 lambda


【解决方案1】:

[=] 确实按值复制,并且您希望本地 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.

我的建议:尽量避免默认捕获模式,因为有一天你会因意外或被遗忘的行为而受到影响。

【讨论】:

    猜你喜欢
    • 2011-08-24
    • 1970-01-01
    • 2013-11-13
    • 2021-11-12
    • 2023-03-03
    • 2018-06-19
    • 1970-01-01
    • 1970-01-01
    • 2014-04-30
    相关资源
    最近更新 更多