Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a mutable lambda with unique_ptr into a const& std::function

Tags:

c++

lambda

c++14

I have got a dispatch function which executes a given lambda in a main thread. For the sake of this question, suppose it looks like the following:

void dispatch(const std::function<void()>& fn) {
    fn();
}

I need to load a new object in a new thread without interrupting the main thread. So I do the following: 1) start a new thread and create a new unique pointer inside the thread, 2) call dispatch and propagate the new unique pointer where it belongs.

std::unique_ptr<std::string> foo; // nullptr

// do the loading in a new thread:
std::thread t([&](){
    // in the new thread, load new value "Blah" and store it temporarily
    auto bar = std::make_unique<std::string>("Blah");
    dispatch([bar2 = std::move(bar), &foo]() mutable {
        foo = std::move(bar2); // propagate the loaded value to foo
    });
});
t.join(); // for the sake of this example

std::cout << "foo = " << *foo << std::endl; // this should say: foo = Blah

Run example online: http://cpp.sh/5zjvm

This code does not compile because the inner lambda in dispatch is mutable and so does not fit into dispatch(const std::function<void()>& fn) which requires a const&.

The lambda, however, needs to be mutable because it needs to call std::move on the unique pointers.

This code could be fixed for example by changing dispatch to:

template <typename Fn>
void dispatch(Fn fn) {
    fn();
}

Unfortunately, the dispatch function is an API of a library and I cannot change it.

Is there a way out of this problem without getting rid of unique pointers?

like image 574
TomsonTom Avatar asked Oct 26 '18 18:10

TomsonTom


People also ask

What happens when you move a unique_ptr?

A unique_ptr can only be moved. This means that the ownership of the memory resource is transferred to another unique_ptr and the original unique_ptr no longer owns it.

What happens when unique_ptr goes out of scope?

A std::unique_ptr owns of the object it points to and no other smart pointers can point to it. When the std::unique_ptr goes out of scope, the object is deleted. This is useful when you are working with a temporary, dynamically-allocated resource that can get destroyed once out of scope.


1 Answers

No, that isn't your problem.

Your problem is that your lambda cannot be copied, as it has a unique ptr captured by value in it.

std::function<Sig> type erases down to

  1. Invoke with Sig

  2. Destroy

  3. Copy (and sometimes move)

  4. Cast-back-to-original-type

Your lambda cannot be copied, so cannot be stored in a std::function.

The lazy-coder's solution is:

    dispatch([bar2 = std::make_shared<decltype(bar)>(std::move(bar)), &foo]() mutable {
        foo = std::move(*bar2);
    });

where we shove the non-copyable state into a shared_ptr.

like image 155
Yakk - Adam Nevraumont Avatar answered Oct 23 '22 18:10

Yakk - Adam Nevraumont