Home > Software design >  Correctly catching the CDatabase::Close exception
Correctly catching the CDatabase::Close exception

Time:10-24

I thought I would do a little digging about cataching exceptions.

According to this question (C catching all exceptions) one of the answers states:

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


At the moment I have used this approach:

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

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

I thought that this was the correct way because when I trace into CDatabase::Close() it does something similar:

// 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);
    }
}

And the CDatabase::Close documentation does not even state anything about exceptions being thrown.


The linked answer does state:

You can use c 11's new current_exception mechanism.

It is not clear if we can use this approach given the CDatabase class we are using.

CodePudding user response:

Since CDatabase::Close() is using THROW_LAST to throw CDBException, you have to use catch (CDBException* e). Even if you are not handling it, you still have to Delete the error. You might as well do this when CDatabase methods are called directly:

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

Or use

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

Because in this code it's not clear where the exceptions are coming from. catch(...) {} will deal with other exceptions. In general catch(...) {} is not recommended because it doesn't give useful information, it just says "something went wrong..."

Use Standard Library exceptions only if you are adding throw in your own code, or when using std functions. Example:

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); }
  • Related