Effective C++ 条款 29:为 “异常安全” 而努力是值得的

条款29:为 “异常安全” 而努力是值得的

当异常被抛出时,带有异常安全性的函数会:

  1. 不泄漏任何资源。
  2. 不允许数据败坏。

异常安全函数提供以下三个基本保证:

  1. 基本承诺:如果异常被抛出,程序内的任何事物仍然保持在有效状态下。没有任何对象或数据结构会因此而破坏。
void basicOperation() {
    std::string s;
    try {
        s = "hello";
        // 如果此处发生异常,s 依然有效,状态未损坏。
    } catch (...) {
        // 异常处理,确保资源安全
    }
}
  1. 强烈保证:如果异常被抛出,程序状态不改变。
class Widget {
public:
    void setName(const std::string& newName) {
        std::string temp(newName); // 创建副本
        swap(*this, name_);         // 确保异常时状态回滚
    }

private:
    void swap(Widget& lhs, Widget& rhs) noexcept {
        std::swap(lhs.data_, rhs.data_); // 假设 std::swap 不抛异常
    }

    std::string name_;
};
  1. 不抛出异常保证:承诺绝不抛出异常。
void nothrowFunction() noexcept {
    // 不可能抛出异常的代码
}

实现强烈保证的技巧

Copy-and-Swap 技术是一种实现强烈保证的常见方式:

  1. 创建副本并在副本上操作。
  2. 使用异常安全的 swap 替换原始对象。
class Widget {
public:
    Widget& operator=(Widget rhs) { // rhs 是副本
        swap(*this, rhs);           // 保证强烈保证
        return *this;
    }

private:
    void swap(Widget& lhs, Widget& rhs) noexcept {
        std::swap(lhs.data_, rhs.data_); // 假设 std::swap 不抛异常
    }

    std::string data_;
};

选择适当的异常安全保证

  1. 基本承诺 是最低要求:在任何情况下,程序都必须保持有效状态。
  2. 强烈保证:如果提供强烈保证可显著提升代码安全性和可读性,且付出的成本合理,应该努力实现。
  3. 不抛异常保证:对于某些特定函数(如析构函数、swap 函数),必须提供不抛异常保证。

异常安全的实现原则

  1. RAII
    将资源管理责任交给 RAII 对象,确保资源释放无论何时都能正确发生。
void safeFunction() {
    std::unique_ptr<Widget> w(new Widget); // 确保异常时资源释放
    // 其他逻辑
}
  1. 事务性操作

    • 函数中的任何修改都以事务形式完成,确保中途失败不影响原始状态。
  2. 封装异常处理逻辑
    避免让调用者直接处理异常,将异常安全性封装在接口中。

  3. 尽量避免动态分配资源
    优先使用标准容器(如 std::vector)和智能指针来管理资源。


注意事项

  1. 异常安全保证的传递性
    函数提供的异常安全性,通常等于其调用的所有子函数中最弱的异常安全保证。

  2. 成本与收益权衡
    并非所有函数都能或需要提供强烈保证。为一些复杂或高性能函数,基本保证可能更实际。

  3. 析构函数必须 nothrow
    确保资源释放阶段不会抛出异常。


总结

  1. 目标:努力使函数具有异常安全性,保护资源完整性和逻辑一致性。
  2. 层次:提供基本承诺、强烈保证或不抛异常保证,视情况而定。
  3. 技术:通过 RAII、copy-and-swap 和事务性操作实现异常安全。
  4. 权衡:在性能、复杂性和安全性之间找到平衡点。

为异常安全而努力,不仅能提高代码健壮性,也能显著减少调试和维护的成本。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值