gpt4 book ai didi

c++ - Lambda 丢失捕获值

转载 作者:行者123 更新时间:2023-11-27 22:34:39 25 4
gpt4 key购买 nike

我不明白为什么捕获的值会丢失。我知道它与范围外或 LambdaWrapper 对象的复制有关。但到底发生了什么?如果 LambdaWrapper(100) 离开了 Add 中的范围并且对 __value 的引用丢失了,那么为什么 LambdaWrapper(300) 就没有了。

#include <iostream>
#include <vector>
#include <functional>
using namespace std;

class LambdaWrapper {
public:
LambdaWrapper(double new_value): __value (new_value) {
cout << "constructed with " << __value << endl;
__func = [this](){ cout << __value << endl;};
}
void call() const { __func(); }
private:
double __value;
function<void(void)> __func;
};

class LambdaContainer {
public:
void Add(double value) {
LambdaWrapper w(value); //out of scope
parts.push_back(w);
}

void Add(LambdaWrapper w) // passed as value
{
parts.push_back(w);
}

void call() const {
for (const auto& part : parts)
part.call();
}
private:
vector<LambdaWrapper> parts;
};

int main() {
LambdaContainer c;
c.Add(100);

LambdaWrapper w(200);
c.Add(w);

c.Add( LambdaWrapper(300) ); //LambdaWrapper(300) will out of scope too

cout << "==============" << endl;
c.call();

return 0;
}

输出:

constructed with 100
constructed with 200
constructed with 300
==============
6.95168e-308 <<< WHY?
200
300

最佳答案

如果 lambda 已经是这样的包装器,为什么还需要这样做呢?为了保留捕获?你做的恰恰相反。

您的闭包,在 Add(double) 内创建方法,捕获 this 的值,它指向调用该方法的对象。当方法超出范围时,该对象“死亡”。该指针的值保持不正确,它是指向本地或临时对象的悬空指针。由于这种设计,其他对象也会发生同样的情况。

LambdaWrapper(const LambdaWrapper &obj) {
__value = obj.__value;
__func = [this](){cout << __value << endl;};
}

此构造函数有效,因为它使用新的 this 创建了新的 lambda例如将持续存在的值。 Lambda 只不过是具有指针字段(大概是 __this )的类实例的语法糖,它存储 this 的值。并包含 void operator() () {cout << __this->__value << endl;};

任何调用 Add(double)会导致悬空指针和 UB,使用时间对象调用也会导致 UB,因为该对象不会与 const 引用绑定(bind)(无论如何它只在本地工作),所以它也是一个悬空指针。该方法按值接受包装器,这导致另一个复制步骤。

该设计不是最理想的,因为每次都会创建一个新对象。如果您只捕获值,则不需要复制构造函数。

附言。作为 lambda 闭包性质的例证,GCC 过去甚至有一个错误\缺陷,其中 lambda 的成员可以从外部访问,因为它们不是私有(private)成员。

关于c++ - Lambda 丢失捕获值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56313174/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com