c++shared-ptrpackaged-task

Can a only-movable object be made into a shared_ptr?


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?


Solution

  • Smart pointers don't even need the element type to be movable. They never attempt to make any copies in any form. All make_shared does is construct an object once and then shared_ptr just pass around a pointer to that single object.

    Copying a shared_ptr is 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 new to create it once and then work through (copies of) the resulting raw pointer.