正确捕获 CDatabase::Close 异常

Correctly catching the CDatabase::Close exception

我想我会做一些关于缓存异常的挖掘。

根据这个问题 (C++ catching all exceptions) 的答案之一是:

[catch(...)] will catch all C++ exceptions, but it should be considered bad design.


目前我使用过这种方法:

CPTSDatabase::~CPTSDatabase()
{
    try
    {
        CloseDatabase();
    }
    catch(...)
    {
    }
}

void CPTSDatabase::CloseDatabase()
{
    if (m_dbDatabase.IsOpen())
        m_dbDatabase.Close();
}

我认为这是正确的方法,因为当我追踪到 CDatabase::Close() 时,它做了类似的事情:

// Disconnect connection
void CDatabase::Close()
{
    ASSERT_VALID(this);

    // Close any open recordsets
    AfxLockGlobals(CRIT_ODBC);
    TRY
    {
        while (!m_listRecordsets.IsEmpty())
        {
            CRecordset* pSet = (CRecordset*)m_listRecordsets.GetHead();
            pSet->Close();  // will implicitly remove from list
            pSet->m_pDatabase = NULL;
        }
    }
    CATCH_ALL(e)
    {
        AfxUnlockGlobals(CRIT_ODBC);
        THROW_LAST();
    }
    END_CATCH_ALL
    AfxUnlockGlobals(CRIT_ODBC);

    if (m_hdbc != SQL_NULL_HDBC)
    {
        RETCODE nRetCode;
        AFX_SQL_SYNC(::SQLDisconnect(m_hdbc));
        AFX_SQL_SYNC(::SQLFreeConnect(m_hdbc));
        m_hdbc = SQL_NULL_HDBC;

        _AFX_DB_STATE* pDbState = _afxDbState;

        AfxLockGlobals(CRIT_ODBC);
        ASSERT(pDbState->m_nAllocatedConnections != 0);
        pDbState->m_nAllocatedConnections--;
        AfxUnlockGlobals(CRIT_ODBC);
    }
}

并且 CDatabase::Close 文档甚至没有说明任何有关抛出异常的信息。


链接的答案说明:

You can use c++11's new current_exception mechanism.

鉴于我们正在使用 CDatabase class,目前尚不清楚我们是否可以使用这种方法。

既然CDatabase::Close()是用THROW_LAST来抛出CDBException,你就得用catch (CDBException* e)。即使你不处理它,你仍然要 Delete 错误。直接调用CDatabase方法的时候不妨这样做:

void CPTSDatabase::CloseDatabase()
{
    try
    {
        if (m_dbDatabase.IsOpen())
            m_dbDatabase.Close();
    }
    catch (CDBException* e) 
    { 
        //TRACE(L"DB error: " + e->m_strError); 
        e->Delete(); 
    }
}

或使用

CPTSDatabase::~CPTSDatabase()
{
    try { CloseDatabase(); }
    catch (CDBException* e) { e->Delete();  }
    catch(...) {}
}

因为在这段代码中并不清楚异常是从哪里来的。 catch(...) {} 将处理其他异常。一般来说 catch(...) {} 不推荐,因为它没有提供有用的信息,它只是说“出了点问题...”

仅当您在自己的代码中添加 throw 或使用 std 函数时才使用标准库异常。示例:

try { std::stoi("wrong argument"); }
catch (const std::exception& e) { TRACE("%s\n", e.what()); }

try { throw 123; }
catch (int i) { TRACE("%d\n", i); }