添加析构函数后vector::emplace_back触发编译错误的原因排查
为何给MyClass2添加自定义析构函数后,
emplace_back触发"result type must be constructible from input type"编译错误 问题本质
当你给MyClass2添加自定义析构函数时,编译器会按照C++规则自动禁用默认移动构造函数和默认拷贝构造函数的生成。而std::vector在扩容时(比如初始容量不足,需要重新分配内存),必须能够移动或拷贝已有元素到新内存区域,此时因为MyClass2没有可用的移动/拷贝构造逻辑,就触发了静态断言错误。
具体原因拆解
- 没有自定义析构函数时,C++编译器会自动生成默认移动构造函数,
std::unique_ptr支持移动操作,所以vector扩容时可以通过移动构造转移元素,不会报错。 - 一旦添加了自定义析构函数,编译器就不再自动生成移动构造/赋值、拷贝构造/赋值。而
MyClass2中的std::unique_ptr是不可拷贝的,默认拷贝构造函数会被自动删除,此时MyClass2既不能被移动也不能被拷贝,vector扩容时无法处理元素迁移,就会抛出这个静态断言错误。
解决方案
你可以根据需求选择以下任一方案:
方案1:添加移动构造函数(推荐,符合unique_ptr的语义)
给MyClass2显式定义移动构造函数,让vector可以通过移动操作完成扩容:
struct MyClass2 { std::unique_ptr<MyClass> my; MyClass2(const MyClass& my2) { my.reset(new MyClass(my2.x)); } ~MyClass2() { printf("deleting\n"); } // 添加移动构造函数 MyClass2(MyClass2&& other) noexcept : my(std::move(other.my)) {} };
方案2:提前预留vector容量,避免扩容
如果确定要插入的元素数量,可以提前调用reserve预留足够空间,这样vector不需要扩容,也就不需要移动/拷贝元素:
int main() { MyClass main(12); std::vector<MyClass2> ts; ts.reserve(10); // 提前预留10个元素的容量 for (int i = 0; i < 10; ++i) { ts.emplace_back(main); } printf("%i\n", ts[0].my->x); return 0; }
方案3:实现深拷贝的拷贝构造函数(如果需要拷贝语义)
如果你需要MyClass2支持拷贝(而不是移动),可以手动实现深拷贝的拷贝构造函数:
struct MyClass2 { std::unique_ptr<MyClass> my; MyClass2(const MyClass& my2) { my.reset(new MyClass(my2.x)); } ~MyClass2() { printf("deleting\n"); } // 深拷贝构造函数 MyClass2(const MyClass2& other) : my(new MyClass(*other.my)) {} };
内容的提问来源于stack exchange,提问作者deanqx
相关产品推荐
相关产品推荐

