1. C++异常安全设计的本质与挑战
异常安全(Exception Safety)是C++资源管理的核心议题,它要求代码在抛出异常时仍能保持系统状态的一致性。我在处理金融交易系统时曾遇到一个典型案例:某次汇率转换操作抛出异常后,账户余额被错误扣减却未完成交易,直接导致对账不平。这个事故让我深刻理解了异常安全的三个关键等级:
- 基本保证:绝不泄漏资源,对象处于有效状态(析构安全)
- 强保证:操作要么完全成功,要么回滚到调用前状态(事务性)
- 不抛保证:承诺绝不抛出异常(如析构函数)
关键认知:异常安全不是可选项,而是现代C++的生存法则。根据Google的代码统计,每100行C++代码平均会抛出0.17个异常。
1.1 资源泄漏的典型场景
观察这段看似无害的代码:
cpp复制void processTransaction() {
Connection* conn = new DatabaseConnection();
conn->execute("UPDATE accounts SET balance..."); // 可能抛出
delete conn; // 异常时跳过
}
当execute()抛出异常时,conn指针将永远泄漏。更糟糕的是,如果异常发生在堆栈回退过程中(如析构函数内抛异常),程序会直接terminate。
1.2 RAII:异常安全的基石
Resource Acquisition Is Initialization(RAII)是解决上述问题的银弹。其核心思想:
- 资源获取即初始化(构造函数中获取)
- 资源释放即析构(析构函数中释放)
- 利用栈对象生命周期自动管理
现代C++的最佳实践:
cpp复制class DBConnection {
public:
static std::shared_ptr<DBConnection> create() {
return std::make_shared<DBConnection>();
}
~DBConnection() { if(connected) close(); }
void execute(const std::string& sql) {
if(sql.empty()) throw std::invalid_argument("Empty SQL");
// 真实操作...
}
private:
DBConnection() { connect(); } // 构造函数私有化
};
2. 智能指针的进阶应用技巧
2.1 unique_ptr的移动语义实战
unique_ptr是独占所有权的最佳载体,我在高频交易系统中通过移动语义实现
