含std::thread成员的类存入std::vector触发已删除构造函数错误?
问题原因分析与解决
首先,核心问题出在C++的特殊成员函数生成规则上,结合std::thread的不可拷贝特性共同导致:
std::thread本身是不可拷贝、仅可移动的类型,所以当你的TEST类包含std::thread成员时,编译器会自动删除TEST的默认拷贝构造函数和拷贝赋值运算符——这部分你已经清楚。- 默认情况下,编译器会为
TEST自动生成默认移动构造函数和默认移动赋值运算符,此时vector的插入操作(比如push_back、emplace_back)可以通过移动语义处理TEST对象,不会触发拷贝,所以单独使用类或者不显式定义析构时不会报错。
为什么显式定义析构函数会触发错误?
C++11及以后的标准规定:如果显式声明了析构函数、拷贝构造函数、拷贝赋值运算符中的任意一个,编译器就不会自动生成默认的移动构造函数和移动赋值运算符。
当你显式定义TEST的析构函数后,TEST同时失去了拷贝构造(被std::thread禁用)和移动构造(编译器不生成)的能力。而vector在插入元素或扩容时,需要将对象从一个内存位置转移到另一个位置——如果没有移动构造函数,编译器会退而求其次尝试调用拷贝构造函数,但拷贝构造已经被删除,于是触发C2280错误(引用已删除的函数)。
为什么emplace_back也会报错?
你可能以为emplace_back是直接在vector内存里构造对象,不会涉及拷贝/移动,但实际场景中:
- 如果
vector当前容量不足以容纳新元素,会触发扩容操作:需要把旧内存中的所有元素转移到新分配的内存中,这时候就需要移动构造函数; - 哪怕是第一次插入,如果你传递的是左值对象给
emplace_back(比如emplace_back(test_obj)而非emplace_back(std::move(test_obj))),编译器仍会尝试调用拷贝构造,而拷贝已经被禁用,所以报错。
解决方案
显式让编译器为TEST生成移动构造和移动赋值运算符,或者手动实现它们:
class TEST { public: std::thread t; // 自定义析构逻辑(如果需要) ~TEST() { if (t.joinable()) { t.join(); } } // 让编译器生成默认移动构造和移动赋值 TEST(TEST&&) = default; TEST& operator=(TEST&&) = default; };
这样vector就可以通过移动语义处理TEST对象,不会再触发拷贝构造的错误。
内容的提问来源于stack exchange,提问作者Runsva
相关产品推荐
相关产品推荐

