std::function 默认对参数进行 copy

在写线程池的时候碰到了这样的报错信息:

1
2
3
error: use of deleted function ‘std::packaged_task<_Res(_ArgTypes ...)>::packaged_task(const std::packaged_task<_Res(_ArgTypes ...)>&) [with _Res = void; _ArgTypes = {}]’

packaged_task(const packaged_task&) = delete;

也就是说我的代码里调用了 packaged_task 的 copy 构造函数,但是它实际上是被删除了,因此导致编译错误;那么哪里会调用 packaged_task 的 copy 构造呢

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 class ThreadPool {
public:
using Task = std::function<void()>;
... ...
private:
... ...
// 任务队列
std::queue<Task> _task_queue;
};
template <typename Function, class... Args>
std::future<typename std::result_of<Function(Args...)>::type>
ThreadPool::add_task(const Function& f, Args... args) {
using Ret = typename std::result_of<Function(Args...)>::type;
std::packaged_task<void()> task(std::bind(f, args...));
std::future<Ret> ret = task.get_future();
{
std::unique_lock<std::mutex> lock(_mu);
_task_queue.push(std::move(task));
_cv.notify_all();
}
return ret;
}

可以看到 _task_queue 的类型是 std::queue<std::function<void()>>,而 std::function 会对传入的参数调用 copy 构造函数,所以它的参数必须是可拷贝的(copy constructible)cppreference然而 packaged_task 不能被 copy 只能被 move,所以会报错

修改方式就是把 std::queue<std::function<void()>> 改成 std::queue<std::packaged_task<void()>> 就可以了;

参考

  1. cppreference——std::function
  2. c++11 threadpool
  3. cppreference——std::packaged_task