C++安全异常设计
🛡️ 异常安全的核心:资源管理
异常发生时,必须确保已申请的资源(内存、文件句柄等)被释放。RAII(Resource Acquisition Is Initialization)是解决此问题的黄金法则。
// 传统方式:易发生资源泄漏 ❌
void unsafeFunc() {FILE* file = fopen("data.txt", "r");throw std::runtime_error("出错!"); // ⚠️ 文件句柄泄漏!fclose(file); // 永远执行不到
}// RAII解法:智能指针自动管理 ✅
#include <memory>
void safeFunc() {auto file = std::unique_ptr<FILE, decltype(&fclose)>(fopen("data.txt", "r"), &fclose);throw std::runtime_error("出错!"); // 文件仍会被fclose自动关闭!
}
💡 异常安全三重保障
等级 | 要求 | 实现方法 |
---|---|---|
基本保证 | 资源不泄漏,对象状态有效 | 析构函数释放资源 (RAII) |
强保证 | 操作成功或完全回滚(原子操作) | Copy-Swap 模式 + RAII |
无异常保证 | 函数绝不抛出异常 | noexcept 声明 + 简单逻辑 |
🧩 实现强保证的Copy-Swap技巧
class DataHolder {
public:void update(const std::vector<int>& newData) {auto temp = std::make_unique<std::vector<int>>(*data_); // 1. 拷贝数据temp->insert(temp->end(), newData.begin(), newData.end()); // 修改副本// 2. 无异常操作:交换指针(确保原子性)std::swap(data_, temp); // ✅ 强保证关键!}
private:std::unique_ptr<std::vector<int>> data_;
};
🚦 关键实践原则
- 析构函数必须为
noexcept
~MyClass() noexcept { /* 清理资源 */ } // 标准库默认如此
- 明确标记不抛异常的函数
void pureCalculation() noexcept { /* 无内存分配/IO操作 */ }
- 切勿在构造函数中抛出异常却未清理资源
- 已在构造中分配的资源需在异常前释放
推荐:C++学习一站式分享