Sterling William
Sterling William

Reputation: 75

free memory of c++ lambda when execute finished

I'm coding a network function on C++, the HTTP request in background thread, use lambda callback when receive HTTP data. But I don't know how to release the lambda, hopes some help.

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;
}

Upvotes: 2

Views: 662

Answers (2)

alagner
alagner

Reputation: 4062

You can capture lambda inside a 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 ?
}

or if it's supposed to be shared, you can use shared ownership semantics via shared_ptr and then capture it into the lambda by value in order to increase its reference count:

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();
}

Of for non-capturing lambdas one can just turn it into a function pointer and don't really care

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();

Upvotes: 7

t.niese
t.niese

Reputation: 40872

the func must be a heap variable for asynchronously.

You first of all should not talk about heap and stack, but about storage duration. This is what is actually important. Heap and stack are implementation details of how this is solved by the implementation.

Capturing all by reference ([&]) for lambda is in many cases a bad idea because you blindly say that you want to use everything in scope by reference. Instead, you should always be explicit about what you want to capture by reference and what by a copy. Especially in the case where the lifetime of the lambda might exceed the variables it can reference.

For the shown code it is not clear why the func is outside the thread and why it has [&]. Both combined indicate that you later want to access a captured variable, and then you just moved the overall problem to a different place.

In the current form, you could just change your code to:

#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;
}

However, for a complex example where you really need func outside of the thread and where you probably need to use some variables in the lambda stored in func that are defined outside of it, your need to add a capture and how you want to capture the things there depends on the exact use case.

Upvotes: 2

Related Questions