[英]C++ Lambda Function closure - memory issue
我是cpp的新手,正在尝试使用lambda函数。 我有一个计数器,我想在lambda函数内部和外部进行递增。 我看到一些奇怪的记忆错误,我无法理解。 这是我处理此计数器的流程。 我做错了什么吗?
bool SomeClass::func() {
int64_t counter = 0;
//some loop logic {
counter++;
}
auto lamb = [this, &counter]() {
//some logic
counter++;
}
someotherFunction(data, lamb); // this function will execute the lambda
}
问题在于,C ++ lambda无法解决“ upper funarg ”问题,即,当通过lambda通过引用捕获了局部变量时,该lambda 保留了局部“所有者”(因为它存储在某个地方或因为它作为函数返回)结果)。
当lambda通过引用捕获变量时,C ++所做的只是将引用变量的地址存储在lambda代码使用的上下文结构中。
但是,在您的情况下,变量本身是局部变量,并且位于创建lambda的堆栈框架中。 如果只是在执行someOtherFunction
过程中调用了lambda对象,那么一切就很好了,但是如果lambda被存储了下来并在创建它的堆栈框架中生存了(或更精确地说,是创建了lambda中引用的捕获变量),当它执行时,将引用一个不再存在的变量(未定义的行为)。
解决一般情况下的“向上funarg”问题需要使用垃圾收集器,而C ++没有垃圾收集器。
在某些情况下,您可以做的是“按值”捕获,因此lambda将拥有自己的私有副本:
foo([counter]() mutable { counter++; })
但是,在这种情况下,如果您想更改捕获的副本,则还需要使用mutable
关键字,因为……好吧,这正是C ++在您要修改捕获的副本时所需要的(捕获的副本否则为const
对象)。 lambda的主体)。
不幸的是,如果您需要与两个lambda共享捕获的变量(例如,在同一捕获的变量上同时创建“增量器”和“减量器”),则使用副本是不可行的。 为此,您可以通过将std::shared_ptr
值捕获到变量中来进行捕获,这将在简单情况下正确替换垃圾收集器(但是,在引用循环的情况下则不然)。
为6502的出色答案添加实用的方法:
auto make_counter(int initial) {
return [initial] (void) mutable {
return ++initial;
};
}
在这里,局部变量(实际上是一个函数参数,但并不重要)是通过值捕获的,这意味着在该lambda的每个对象内部都有一个副本。 为了能够增加计数器,lambda必须允许对其捕获变量进行修改,从而使mutable
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.