执行完成后释放 C++ lambda 的内存

free memory of c++ lambda when execute finished

我正在用 C++ 编写一个网络函数,后台线程中的 HTTP 请求,在接收 HTTP 数据时使用 lambda 回调。但我不知道如何释放lambda,希望得到一些帮助。

void foo()
{
    // the `func` must be a heap variable for asynchronously.
    auto func = new auto ([&](std::string response){
        printf("recv data: %s", response.c_str());
    });
    
    std::thread t([&]{
        sleep(2);   // simulate a HTTP request.
        std::string ret = "http result";
        (*func)(ret);
    });
    t.detach();
    
    // The foo function was finished. bug `func` lambda still in memory ?
}

int main()
{
    foo();
    getchar(); // simulate UI Event Loop.
    return 0;
}

您可以在 lambda 中捕获 lambda:

void foo()
{
    std::thread t(
        [func = [](std::string response) {
            printf("recv data: %s", response.c_str());
        }](){
        sleep(2);   // simulate a HTTP request.
        std::string ret = "http result";
        func(ret);
    });
    t.detach();
    // The foo function was finished. bug `func` lambda still in memory ?
}

或者如果它应该被共享,您可以通过 shared_ptr 使用共享所有权语义,然后按值将其捕获到 lambda 中以增加其引用计数:

void foo()
{
    auto lambda = [](std::string response){
                printf("recv data: %s", response.c_str());
            };
    
    std::shared_ptr<decltype(lambda)> func{
        std::make_shared<decltype(lambda)>(std::move(lambda))
    };

    std::thread t([func]{
        sleep(2);   // simulate a HTTP request.
        std::string ret = "http result";
        (*func)(ret);
    });
    t.detach();
}

对于 非捕获 lambdas 可以将它变成一个函数指针,并不关心

void foo()
{
    auto func_{
        [](std::string response){
            printf("recv data: %s", response.c_str());
        }
    };
    
    std::thread t([func=+func_]{ //note the + to turn lambda into function pointer
        sleep(2);   // simulate a HTTP request.
        std::string ret = "http result";
        (*func)(ret);
    });
    t.detach();

the func must be a heap variable for asynchronously.

你首先不要说堆和栈,而是说存储时长。这才是真正重要的。堆和栈是实现如何解决这个问题的实现细节。

对于 lambda,通过引用捕获所有内容 ([&]) 在许多情况下不是一个好主意,因为你盲目地说你想通过引用使用范围内的所有内容。相反,您应该始终明确说明要通过引用捕获什么以及通过副本捕获什么。特别是在 lambda 的生命周期可能超过它可以引用的变量的情况下。

对于显示的代码,不清楚为什么 func 在线程之外以及为什么它有 [&]。两者结合表明您稍后想要访问捕获的变量,然后您只是将整个问题移到了不同​​的地方。

在当前表格中,您只需将代码更改为:

#include <thread>
#include <cstring>
#include <string>
#include <unistd.h>

void foo()
{
    // removed & to not capture any variables
    auto func = [](std::string response){
        printf("recv data: %s", response.c_str());
    };
    
    // replaced & by func to copy the lambda
    std::thread t([func]{
        sleep(2);   // simulate a HTTP request.
        std::string ret = "http result";
        func(ret);
    });
    t.detach();
}

int main()
{
    foo();
    getchar(); // simulate UI Event Loop.
    return 0;
}

但是,对于一个复杂的示例,您确实需要在线程外使用 func,并且您可能需要在存储在 func 中的 lambda 中使用一些在线程外定义的变量,您是否需要添加捕获以及您希望如何捕获那里的东西取决于具体的用例。