lambda的捕获变量被重置

马可·卢扎拉(Marco Luzzara)

我正在尝试lambda在项目中使用s,但我想我缺少有关闭包范围的信息。我测试了这段代码,以某种方式简化了我的问题。

#include <iostream>
#include <functional>

using namespace std;

void tester_wrapper(std::function<int(void)> cb, int counter){
    if (counter == 10)
        return;
    else{
        cout << cb() << endl;
        tester_wrapper(cb, counter + 1);
    }
}

void tester(std::function<int(void)> cb){
    tester_wrapper(cb, 0);
}

int main()
{
    auto getNum = ([](int starter) {
        return [starter]() mutable {
            return ++starter;
        };
    })(1);

    tester(getNum);
    tester(getNum);
}

首次调用tester捕获的变量后,starter将重置该输出,以便将相同的输出打印两次。

为了避免starterlambda的内部counter()的这种行为,我该怎么办本质上,第二个呼叫tester必须打印从12开始的10个数字,而不是2。


编辑

感谢您的回答。我没有考虑过将副本传递给tester_wrapper,所以找到了以下解决方案:

#include <iostream>
#include <functional>

using namespace std;

std::function<int(void)> mylambda(int starter){
    return [starter]() mutable {
        return ++starter;
    };
}

void tester_wrapper(const std::function<int(void)>& cb, int counter){
    if (counter == 10)
        return;
    else{
        cout << cb() << endl;
        tester_wrapper(cb, counter + 1);
    }
}

void tester(const std::function<int(void)>& cb){
    tester_wrapper(cb, 0);
}

int main()
{
    /*auto getNum = ([](int starter) {
        return [starter]() mutable {
            return ++starter;
        };
    })(1);*/

    auto getNum = mylambda(1);

    tester(getNum);
    tester(getNum);
}

但是,现在我不明白为什么旧getNum的使用“外部”功能(即)输出相同的输出,而输出不同mylambda

(我应该为此发布一个新问题吗?)

讲故事的人-Unslander Monica

变量不会重置,而是变量的不同副本。实际上,有一堆副本。第一个处于您创建的lambda的状态。第二个是在std::function构造第一个时创建的您必须记住,它将接收到的可调用对象复制到其自身中。因此,每次调用都会tester启动一连串的副本。解决该问题的一种方法是将lambda传递到std::reference_wrapper

tester(std::ref(getNum));
tester(std::ref(getNum));

参考包装器将被复制,但是所有副本都将引用同一个lambda对象getNum

现在,假设您打算创建许多不同的对象(如)getNumstd::function并且提供的类型擦除是一种合理的操作方法,可以避免可能的代码膨胀。要记住的是不要创建多余的副本。因此,tester按价值接受是合法的,但tester_wrapper应改为按引用接受。这样一来,您只需在API边界的所需位置购买类型擦除即可。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章