使用 noexcept 在移动构造函数中有几个重要原因:
std::vector<Vector<int>> vec;
vec.push_back(Vector<int>()); // 如果需要扩容,std::vector 会选择移动而不是拷贝
- 当 std::vector 需要扩容时,它需要将元素移动到新的内存位置
- 如果移动构造函数标记为 noexcept,std::vector 会使用移动操作
- 如果没有标记 noexcept,为了保证强异常安全性,std::vector 会退化为使用拷贝操作
2. 性能优化
- 移动操作通常是简单的指针和整数赋值,不会抛出异常
- 标记 noexcept 可以让编译器生成更优化的代码
3. 语义保证
// 移动赋值运算符也应该是 noexcept
Vector& operator=(Vector&& other) noexcept {
if (this != &other) {
delete[] data_; // 不会抛出异常
// 简单的赋值操作
size_ = other.size_;
capacity_ = other.capacity_;
data_ = other.data_;
other.size_ = 0;
other.capacity_ = 0;
other.data_ = nullptr;
}
return *this;
}
4. 与标准库一致性
static_assert(std::is_nothrow_move_constructible<Vector<int>>::value,
"Vector should be nothrow move constructible");
5. 示例:std::vector 的行为
std::vector<Vector<int>> containers;
containers.reserve(10); // 预分配空间
Vector<int> v;
// 如果 Vector 的移动构造是 noexcept
containers.push_back(std::move(v)); // 使用移动构造
// 如果 Vector 的移动构造不是 noexcept
containers.push_back(std::move(v)); // 可能使用拷贝构造!
void swap(Vector& other) noexcept { // swap 也应该是 noexcept
std::swap(size_, other.size_);
std::swap(capacity_, other.capacity_);
std::swap(data_, other.data_);
}
- 移动操作通常用于实现异常安全的代码
- 如果移动操作可能抛出异常,会使异常安全的实现变得更困难
No comments yet.