vendredi 26 mars 2021

c++: Efficient way to passing shared_ptr to a lambda

I've created a small program years ago, and I've recently stared to use smart pointers. So for practice reasons I refactored some part of the code based on Scott Meyers - Effective Modern C++ book.

Imagine a class, that holds a member shared_ptr of another class, that manages the life cycle of some other unnecessary objects.

class Foo {
...
    std::shared_ptr<Bar> manager;

    void DoSomeWork();
}

The implementation of the DoSomeWork method contains a lambda collectIfNeighbor, because it is used frequently in some parts, and this was the easiest way to achieve the correct behavior. The main idea was to capture only what is needed in the lambda and use smart pointers instead of nullptr checks everywhere.

void Foo::DoSomeWork(){
    std::vector<Object*> neighbors;
    auto collectIfNeighbor = [this, &neighbors](const Position& pos) {
        ...    
        if ( *some condition* )
            neighbors.push_back(manager->GetObject(pos));
    };
    collectIfNeighbor(Position(1,1));    // example usage
    ...
}

So the problem here is that inside the lambda I capture this, but I don't really need the whole, just the manager. What is the most efficient way to pass a shared_ptr to a lambda?

If possible I do not want to pass the whole this because I use only one member. Either I do not want to create and destroy tons of shared_ptrs, because it would make it slower. Also, it would be nice not to care about manager is still alive or not.

There were other approaches to the lambda implementation. Copy the shared_ptr to a local one, and passing it by reference. But I make and additional copy locally, and I'm afraid every time when the lambda called. Another approach was to simply create a regular pointer and passing that to the lambda.

std::shared_ptr<Bar> localManager = manager;
auto lambdaV1= [&localManager, &neighbors](const Position& pos) {
    ...    
    if ( *some condition* )
        neighbors.push_back(manager->GetObject(pos));
};
Bar* localManagerPtr = manager.get();
auto lambdaV2= [&localManagerPtr , &neighbors](const Position& pos) {
    ...    
    if ( *some condition* && manager != nullptr)    // extra check on manager
        neighbors.push_back(manager->GetObject(pos));
};

I checked Passing shared_ptr to lambda cause memory leak and Capture by universal ref however it didn't helped me much.

Aucun commentaire:

Enregistrer un commentaire