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?
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.
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.
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
Invoke with Sig
Destroy
Copy (and sometimes move)
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With