C++ C++;Lambda函数关闭-内存问题

C++ C++;Lambda函数关闭-内存问题,c++,lambda,C++,Lambda,我是cpp新手,尝试使用lambda函数。我有一个计数器,我试图在lambda函数内部和外部递增。我看到一些奇怪的记忆错误,我无法理解。这是我使用这个计数器的流程。有什么我做错了吗 bool SomeClass::func() { int64_t counter = 0; //some loop logic { counter++; } auto lamb = [this, &counter]() { //s

我是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++ LAMBDAS无法解决“”情况,即当本地变量被lambda引用时,该Labbda在本地的“所有者”中幸存(因为它存储在某处,或者因为它作为函数结果返回)。

当lambda通过引用捕获变量时,C++所做的只是将引用变量的地址存储在lambda代码使用的上下文结构中。

然而,在您的例子中,变量本身是一个局部变量,并且存在于创建lambda的堆栈帧中。如果lambda对象是在执行
someOtherFunction
期间调用的,则一切正常,但如果lambda存储在之外,并在创建它的堆栈帧中生存(或者更准确地说,是创建lambda中引用的捕获变量),当它被执行时,将引用一个不再存在的变量(未定义的行为)

解决一般情况下的“上FunARG”问题需要垃圾回收器,C++没有一个。 在某些情况下,您可以通过“按值”捕获,因此lambda将拥有自己的私有副本:

foo([counter]() mutable { counter++; })
但是,在这种情况下,如果要更改捕获的副本,还需要使用
mutable
关键字,因为。。。因为这是C++需要的,如果你想修改捕获的副本(捕获的拷贝是其他代码<代码> const 对象在lambda的身体中。

不幸的是,如果您需要共享捕获的变量,例如与两个lambda共享(例如,在同一个捕获的变量上同时创建“递增器”和“递减器”),则使用副本是不可行的。
为此,您可以通过将值a
std::shared_ptr
捕获到变量,这将正确地替换简单情况下的垃圾收集器(但不是在引用循环的情况下)。

为6502的优秀答案添加了一种实用方法:

auto make_counter(int initial) {
  return [initial] (void) mutable {
    return ++initial;
  };
}

在这里,局部变量(实际上它是一个函数参数,但并不重要)由值捕获,这意味着在lambda的每个对象中都有一个它的副本。为了能够增加计数器,lambda必须允许对其捕获的变量进行修改,因此
可变

如何解决这个问题?那么,有没有办法将局部变量的值传递给lambda?当您提到使用共享指针时,您是说这样做的:
auto pin=std::make_shared(counter)和按值捕获
pin
@6502@Anzurio:是的。如果lambda生存期本身不是由共享指针处理的,而共享指针可能会使用捕获的对象创建引用循环,那么按值捕获
共享\u ptr
是可以的(C++不提供垃圾收集器,因此丢弃的refcounted循环是泄漏的)。编写此函数时,它应该可以工作-因为如果在
其他函数中执行
lamb
,则
计数器仍将在作用域内。但是,如果
someotherFunction
正在存储lambda,然后在
func
返回后,lambda被执行,那么您就有一个悬而未决的引用问题。但是看看下面的注释,似乎如果某个其他函数的执行时间比func的执行时间长,那么它将失败,对吗?关键是您正在从
func
内部调用
someotherFunction
,这意味着它不能比
func
的执行时间长。