ThreadPool实现中~__nat()已删除错误的排查咨询
线程池实现中的clang编译错误分析(~__nat()已删除)
我正在实现一个线程池,clang编译器抛出了无法理解的~__nat()已删除错误。这个线程池包含1个负责规划并向队列添加任务的Scheduler线程、1个负责从队列取出任务并分配子线程的Executor线程,以及每个任务对应的子线程,问题出在Executor模块:
struct Executor { std::shared_ptr<SharedData> data_ptr_; // constructor explicit Executor (std::shared_ptr<SharedData>& data_ptr): data_ptr_ (data_ptr) {} // methods void execute () { while (true) { auto cur_task = data_ptr_->queue_.Take(); if (cur_task == std::nullopt) break; std::thread child_thread {&Executor::executeChild, this, std::move(cur_task)}; // ... } // join child threads here } void executeChild (Task task) { // ... task(); // ... } };
编译器对std::thread child_thread {&Executor::executeChild, this, std::move(cur_task)};这行代码报错,错误信息如下:
In template: attempt to use a deleted function error occurred here in instantiation of function template specialization 'std::__thread_execute<std::unique_ptr<std::__thread_struct>, void (tp::Executor::*)(fu2::detail::function<fu2::detail::config<true, false, fu2::capacity_default>, fu2::detail::proper... in instantiation of function template specialization 'std::__thread_proxy<std::tuple<std::unique_ptr<std::__thread_struct>, void (tp::Executor::*)(fu2::detail::function<fu2::detail::config<true, false, fu2::capacity_default>, fu2::detai... in instantiation of function template specialization 'std::thread::thread<void (tp::Executor::*)(fu2::detail::function<fu2::detail::config<true, false, fu2::capacity_default>, fu2::detail::property<true, false, void ()>>), tp::Executor ... '~__nat' has been explicitly marked deleted here
错误原因与解决方法
报错本质:
~__nat()已删除是clang底层模板实例化失败的间接报错,核心问题是std::thread构造时无法正确处理你传递的参数组合,不是__nat本身的问题,而是上层参数传递触发了模板内部的删除函数调用。代码错误点:
- 参数类型不匹配:
cur_task是std::optional<Task>,但executeChild的参数是Task。虽然你判断了cur_task不为空,但std::thread在构造时会尝试将参数打包到内部存储,std::optional的移动操作无法直接适配成员函数的Task参数要求,导致模板实例化失败,触发了底层的删除函数错误。 - 子线程生命周期隐患:当前代码中创建的
child_thread是局部变量,循环迭代结束后会被销毁,此时线程若未join或detach会直接终止程序,这是后续运行时的问题,但当前编译错误的直接原因是参数传递。
- 参数类型不匹配:
解决步骤:
- 先解包
std::optional获取Task对象:
修改线程构造代码,把std::move(cur_task)改成std::move(*cur_task),确保传递的是Task类型而非std::optional<Task>:auto cur_task = data_ptr_->queue_.Take(); if (cur_task == std::nullopt) break; std::thread child_thread {&Executor::executeChild, this, std::move(*cur_task)}; - 存储子线程并统一join:
把创建的子线程存入容器,避免局部变量销毁导致的线程终止,在循环结束后统一等待所有子线程完成:void execute () { std::vector<std::thread> child_threads; while (true) { auto cur_task = data_ptr_->queue_.Take(); if (cur_task == std::nullopt) break; child_threads.emplace_back(&Executor::executeChild, this, std::move(*cur_task)); } // join child threads here for (auto& t : child_threads) { if (t.joinable()) { t.join(); } } } - 确保Executor对象生命周期:如果
Executor本身不是被shared_ptr管理,子线程运行时this指针可能失效,建议将Executor用std::shared_ptr持有,或者把executeChild改为静态函数,传递std::shared_ptr<SharedData>和Task,避免依赖this指针。
- 先解包
内容的提问来源于stack exchange,提问作者Amir Mokhammed-Ali
相关产品推荐
相关产品推荐

