I am reading open source code of thread_pool
And it shows
// add new work item to the pool
template<class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type>
{
using return_type = typename std::result_of<F(Args...)>::type;
auto task = std::make_shared< std::packaged_task<return_type()> >(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);
std::future<return_type> res = task->get_future();
{
std::unique_lock<std::mutex> lock(queue_mutex);
// don't allow enqueueing after stopping the pool
if(stop)
throw std::runtime_error("enqueue on stopped ThreadPool");
tasks.emplace([task](){ (*task)(); });
}
condition.notify_one();
return res;
}
As far as I know, std::packaged_task is a only movable object, so could a shared_ptr of task be made of std::packaged_task?Because std::packaged_task could never be shared.
But in an oppisite way, in sentence tasks.emplace([task](){ (*task)(); });, task is value-copied into lambda, so does it also mean the count in shared_ptr of task will be added into 2?Which means std::packaged_task is actually be shared into 2 copies.
So can a only-movable object be made into a shared_ptr?Are there any wrong place in my above thoughts?
Smart pointers don't even need the element type to be movable. They never attempt to make any copies in any form. All
make_shareddoes is construct an object once and thenshared_ptrjust pass around a pointer to that single object.Copying a
shared_ptris just like copying a raw pointer (plus the reference counting of course). It doesn't make a copy of the pointed-to object.You wouldn't need the type to be copyable or movable either if all you did manually was to use
newto create it once and then work through (copies of) the resulting raw pointer.