移动构造函数何时必须声明为noexcept
为什么C++标准建议将移动构造函数和移动赋值重载标记为noexcept?如果不标记noexcept,std::vector在扩容时会发生什么行为退化和性能损失?
回答
古法程序员
std::vector::reserve/push_back扩容时,如果移动构造函数是noexcept,vector优先使用移动构造转移元素(高效,窃取资源+将源置空)。如果移动构造函数不保证noexcept,vector必须使用拷贝构造作为回退——因为如果移动构造抛出异常,vector已修改的内部状态无法安全恢复(弱保证vs强保证)。后果:①拷贝构造可能更昂贵(如深拷贝大量数据);②无法窃取资源。C++标准规定:std::vector的reserve/insert/push_back操作提供强异常安全保证——如果移动操作不保证noexcept,则使用拷贝操作来保证异常安全性。C++17起std::optional也有类似行为。建议:所有移动构造函数和移动赋值操作符都应标记noexcept(移动操作通常只交换指针,不应失败)。std::unique_ptr的移动构造已标记noexcept。