禁用拷贝语义后,继承场景下std::vector的emplace_back为何失效?
问题原因分析
核心问题在于C++中特殊成员函数的自动生成规则,以及std::vector对移动语义的要求:
1. 显式声明析构函数会抑制默认移动构造的生成
当你在MyClass中显式定义了析构函数~MyClass() override {}时,C++编译器会停止自动生成默认的移动构造函数和移动赋值运算符。
- 虽然基类
NonCopyable有默认的移动构造,但派生类不会自动继承或生成对应的移动构造。此时MyClass实际上没有可用的移动构造函数。
2. std::vector的扩容依赖可用的移动/拷贝语义
std::vector在需要扩容时(比如emplace_back导致容量不足),需要将现有元素转移到新内存中:
- 优先使用
noexcept的移动构造函数; - 如果没有可用的移动构造,会尝试使用拷贝构造函数——但
MyClass继承了NonCopyable的拷贝构造删除,因此编译报错。
3. MyClass2正常的原因
MyClass2显式声明了MyClass2(MyClass2 &&) noexcept = default;,即使有自定义析构函数,编译器仍会生成符合要求的移动构造函数,满足std::vector对移动语义的需求,因此编译正常。
4. 注释析构函数后正常的原因
当你注释掉MyClass的析构函数时,MyClass没有显式声明任何特殊成员函数(析构、拷贝、移动),编译器会自动生成默认的移动构造函数:
- 这个默认移动构造会调用基类的移动构造,且默认是
noexcept的,完全符合std::vector的要求。
修复方案
给MyClass显式添加默认的移动构造和移动赋值即可:
class MyClass : public NonCopyable { public: MyClass() = default; ~MyClass() override {} // 显式声明默认移动构造和赋值 MyClass(MyClass &&) noexcept = default; MyClass &operator=(MyClass &&) noexcept = default; };
内容的提问来源于stack exchange,提问作者Enmaniac
相关产品推荐
相关产品推荐

