c++ - lambda 的捕获变量被重置

标签 c++ c++11 lambda closures

我正在尝试在项目中使用 lambda,但我认为我遗漏了有关闭包范围的一些信息。我测试了这段代码,它在某种程度上简化了我的问题。

#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 被重置,因此相同的输出被打印两次。

我应该怎么做才能避免 lambda 的内部计数器 (starter) 的这种行为?本质上,对 tester 的第二次调用必须打印从 12 而不是 2 开始的 10 个数字。


编辑

感谢您的回答。我没有考虑过将拷贝传递给 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)却有所不同。

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

最佳答案

变量没有被重置,它是变量的不同拷贝。事实上,有一堆拷贝。第一个是您创建的 lambda 的状态。第二个是在构造第一个 std::function 时创建的。您必须记住,它将接收到的可调用对象复制到自身中。因此每次调用 tester 都会启动一个拷贝链。绕过它的一种方法是在 std::reference_wrapper 中传递 lambda。 .

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

将复制引用包装器,但所有拷贝都将引用同一个 lambda 对象,getNum

现在,假设您打算创建许多不同的对象,如 getNumstd::function 和它提供的类型删除是避免可能的合理操作过程代码膨胀。要记住的是不要创建多余的拷贝。所以 tester 按值接受是合法的,但 tester_wrapper 应该改为按引用接受。这样一来,您只需在 API 边界需要的地方为类型删除付费。

关于c++ - lambda 的捕获变量被重置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48241935/

相关文章:

c++ - 如何在 C++ 14 上获取 -nan?

c++ - 如何复制 boost 信号的槽

c++ - 动态类成员

c++ - 将具有绑定(bind)成员函数的 std::bind 对象传递给函数

c++ - lambda 尾随返回类型 auto 的用法是什么?

java - 像在 SQL 中使用 Java lambda 一样对对象进行分组和求和?

java - 合并 Map<String, List<String> Java 8 Stream

c++ - 几分钟后动态分配的工作线程泄漏,尽管它不应该

C++ 测试是否可除以 double

c++ - 移动 vector 是否会使迭代器无效?