C++编译错误:尝试引用已删除函数及死锁问题求助
问题解决:编译错误与死锁问题
问题描述
编译时出现attempting to reference a deleted function错误,同时调用P类的del函数会触发死锁。
编译错误信息
C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.26.28801\include\xmemory(671): error C2280: 'C::C(const C &)': attempting to reference a deleted function C:\Users\HARSHA\Desktop\LC\2022\A\C.h(33): note: compiler has generated 'C::C' here C:\Users\HARSHA\Desktop\LC\2022\A\C.h(33): note: 'C::C(const C &)': function was implicitly deleted because a data member invokes a deleted or inaccessible function 'std::thread::thread(const std::thread &)' C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.26.28801\include\thread(93): note: 'std::thread::thread(const std::thread &)': function was explicitly deleted
编译错误解决
错误原因
- C类拷贝构造被删除:C类包含
std::thread成员,std::thread的拷贝构造函数是显式删除的,因此编译器自动删除了C类的隐式拷贝构造函数,代码中潜在的拷贝操作触发了错误。 - 不完整类型成员:C.h中未包含
Location.h,直接声明struct location loc;,location属于不完整类型,无法作为类的成员变量,导致编译类型检查出错。 - P类拷贝初始化问题:Main.cpp中
P p = P();是拷贝初始化,而P类包含不可拷贝的std::mutex成员,其拷贝构造函数已被隐式删除,该写法会触发潜在拷贝错误。
修复步骤
完善C.h的头文件依赖:在
C.h顶部添加#include "Location.h",确保location是完整类型:#ifndef A_C_H #define A_C_H #include <string> #include <thread> #include <chrono> #include <atomic> #include "Location.h" // 添加该行 class P; // ... 其余代码不变显式禁用C类的拷贝操作:在C类的public区域添加拷贝构造和赋值运算符的删除声明,避免意外触发拷贝:
class C { // ... 私有成员不变 public: C() = default; ~C() = default; C(const C&) = delete; // 添加该行 C& operator=(const C&) = delete; // 添加该行 // ... 其余成员函数不变 };修改Main.cpp的P对象初始化方式:将
P p = P();改为直接默认构造,避免拷贝初始化:int main() { P p; // 替换原有的P p = P(); p.add_child("C1"); p.add_child("C2"); p.add_child("C3"); char input; std::cin >> input; p.del(); }
死锁问题解决
死锁原因
P::del()函数中,主线程先获取mut互斥锁,然后调用c->wait()等待子线程结束;而子线程的run()函数中会调用p->get_data(),该函数需要获取mut互斥锁。此时主线程持有锁等待子线程,子线程等待锁释放,形成循环等待,触发死锁。
修复步骤
修改P::del()函数,拆分锁的持有范围:先加锁设置终止标志,释放锁让子线程完成退出逻辑,最后再加锁清理列表:
void P::del() { // 第一步:加锁设置终止标志 { std::lock_guard<std::mutex> lg(mut); for (auto& c : C_List) c->terminate = true; } // 此处自动释放锁,子线程可获取锁执行get_data() // 第二步:等待所有子线程退出,无需持有锁 for (auto& c : C_List) c->wait(); // 第三步:重新加锁清理列表 std::lock_guard<std::mutex> lg(mut); C_List.clear(); }
内容的提问来源于stack exchange,提问作者Harry
相关产品推荐
相关产品推荐

