测试_第23章_异常安全.cpp

← 测试总览 · 目录

编译运行:clang++ -std=c++26 -Wall -Wextra -pthread 测试_第23章_异常安全.cpp -o t && ./t(需先 cd 测试/

// 第23章测试:异常安全与 RAII 深入
#include <print>
#include <string>
#include <vector>
#include <memory>
#include <stdexcept>

int failures = 0;
#define CHECK(expr)                                                         \
    do {                                                                    \
        if (!(expr)) {                                                      \
            ++failures;                                                     \
            std::println("FAIL 第{}行: {}", __LINE__, #expr);              \
        }                                                                   \
    } while (0)

// 23.3 银行转账(先验证后提交 → 强保证)
class Account {
public:
    explicit Account(double b) : balance_(b) {}
    void withdraw(double amt) { balance_ -= amt; }   // 不检查(调用方先验证)
    void deposit(double amt) { balance_ += amt; }
    double balance() const { return balance_; }
private:
    double balance_ = 0;
};

void transfer_safe(Account& a, Account& b, double amt) {
    if (a.balance() < amt) throw std::runtime_error("余额不足");
    // 所有可能失败的检查都已前置 → 下面不再抛异常 → 强保证
    a.withdraw(amt);
    b.deposit(amt);
}

// 23.4 copy-and-swap
class Widget {
public:
    Widget() = default;
    explicit Widget(int n) : data_(n, 7) {}
    Widget(const Widget&) = default;
    Widget& operator=(Widget other) {
        swap(other);
        return *this;
    }
    void swap(Widget& o) noexcept { data_.swap(o.data_); }
    std::size_t size() const { return data_.size(); }
    int first() const { return data_.front(); }
private:
    std::vector<int> data_;
};

// 23.5 RAII 事务(模拟数据库)
class FakeDb {
public:
    bool in_tx() const { return tx_open_; }
    void begin() { tx_open_ = true; committed_ = false; }
    void insert(const std::string& s) { log_.push_back(s); }
    void commit() { committed_ = true; tx_open_ = false; }
    void rollback() { if (tx_open_) { log_.clear(); tx_open_ = false; } }
    std::size_t log_size() const { return log_.size(); }
private:
    bool tx_open_ = false;
    bool committed_ = false;
    std::vector<std::string> log_;
};

class Transaction {
public:
    explicit Transaction(FakeDb& db) : db_(db) { db_.begin(); }
    ~Transaction() {
        if (!committed_) db_.rollback();    // 忘了 commit → 自动回滚
    }
    void commit() { committed_ = true; db_.commit(); }
private:
    FakeDb& db_;
    bool committed_ = false;
};

// 23.9 SafeStack
template <typename T>
class SafeStack {
public:
    void push(const T& v) { data_.push_back(v); }   // vector 自带强保证
    void pop() {
        if (data_.empty()) throw std::runtime_error("空栈");
        data_.pop_back();
    }
    const T& top() const {
        if (data_.empty()) throw std::runtime_error("空栈");
        return data_.back();
    }
    std::size_t size() const { return data_.size(); }
private:
    std::vector<T> data_;
};

int main() {
    // 23.3 强保证转账
    Account a(100), b(50);
    transfer_safe(a, b, 30);                        // 成功
    CHECK(a.balance() == 70 && b.balance() == 80);
    bool threw = false;
    try {
        transfer_safe(a, b, 500);                   // 余额不足
    } catch (const std::runtime_error&) { threw = true; }
    CHECK(threw);
    CHECK(a.balance() == 70 && b.balance() == 80);  // 状态没变:强保证!

    // 23.4 copy-and-swap
    Widget w1(3);
    Widget w2;
    w2 = w1;                                        // 拷贝赋值
    CHECK(w2.size() == 3 && w2.first() == 7);
    w2 = Widget(5);                                 // 临时对象赋值
    CHECK(w2.size() == 5);

    // 23.5 RAII 事务
    FakeDb db;
    {
        Transaction tx(db);
        db.insert("record1");
        // 不 commit → 析构自动回滚
    }
    CHECK(db.log_size() == 0);                      // 回滚了
    {
        Transaction tx(db);
        db.insert("record2");
        tx.commit();
    }
    CHECK(db.log_size() == 1);                      // 提交保留

    // 23.9 SafeStack 异常路径
    SafeStack<int> st;
    CHECK(st.size() == 0);
    try {
        st.pop();                                   // 空栈 → 抛异常
        CHECK(false);
    } catch (const std::runtime_error&) { CHECK(true); }
    st.push(1);
    st.push(2);
    CHECK(st.size() == 2);
    CHECK(st.top() == 2);
    st.pop();
    CHECK(st.top() == 1);

    // 23.10 构造失败不泄漏(成员 RAII 自动清理)
    struct Exploder {
        struct Sub { ~Sub() { /* 资源释放 */ } };
        std::unique_ptr<int> mem = std::make_unique<int>(1);
        Sub sub;
        Exploder() { throw std::runtime_error("构造失败"); }
    };
    try { Exploder e; (void)e; CHECK(false); }
    catch (const std::runtime_error&) { CHECK(true); }
    // 构造失败后,mem 与 sub 正常析构(内存无泄漏)

    if (failures == 0) std::println("全部通过");
    return failures;
}