从 RAII 类的析构函数引发异常

Throwing exception from destructor of RAII class

本文关键字:异常 析构函数 RAII      更新时间:2023-10-16

我创建了一个类来封装数据库事务,以确保在抛出异常时回滚或提交它。问题是创建和关闭事务都可能失败。由于事务正在析构函数中关闭,因此如何在不引发异常的情况下处理失败?显然,如果由于堆栈下方某处抛出异常而导致TransactionLock对象被销毁,这将导致程序终止。

// RAII class for database transaction
class TransactionLock {
public:
    TransactionLock(QSqlDatabase& db) :
        m_db(db),       
        m_query(db),
        m_committed(false)
    {
        bool ok = m_query.exec("BEGIN IMMEDIATE TRANSACTION");
        if (!ok)
        {
            throw IOException(m_query.lastError());
        }
    }
    ~TransactionLock() 
    {
        bool ok = m_committed ? m_db.commit() : m_db.rollback();
        // if (!ok) throw?
    }
    void commitTransaction()
    { 
        m_committed = true;
    }       
private:
    QSqlDatabase& m_db; 
    QSqlQuery m_query;
    bool m_committed;   
};

你永远不应该抛入析构函数。不仅因为析构函数可以作为异常堆栈展开的结果而被调用,还因为它在逻辑上是无意义的。

您无法阻止对象被破坏,因此异常根本不会给您任何东西。在你的特殊情况下,你需要重新设计你的类。标准方法通常是在析构函数中执行自动回滚。提交事务是带有错误代码的显式操作。