Listing 3

template< class TDatabaseEnvironment > 
class CTransaction 
{ 
public: 
  inline explicit       CTransaction 
    ( 
    CTransaction< TDatabaseEnvironment > *  pOptionalParent = 0, 
    u_int32_t                               Flags = 0 
    ); 
  inline void   Commit( u_int32_t CommitFlags = 0 ); 
  inline void   Abort(); 
  
  // Destructor will abort transaction if Commit() or Abort()
  // not explicitly called first. 
  inline        ~CTransaction(); 
private: 
  CTransaction< TDatabaseEnvironment > *  m_pOptionalParent; 
  DbTxn *                                 m_pDbTxn; 
  // Disable copying and assignment.
               CTransaction( const CTransaction & ); 
  CTransaction &  operator=( const CTransaction & ); 

  // Transactions are normally scoped stack objects. However, there are
  // times when we need to put them on the heap (held by auto_ptr or 
  // shared_ptr for for scoping) 
  // So we only disable array new and delete, not single new and delete. 
  static void *  operator new[]( size_t nSize ); 
  static void    operator delete[]( void *pArray ); 
}; 
template< class TDatabaseEnvironment > 
CTransaction< TDatabaseEnvironment >::CTransaction 
  ( 
  CTransaction< CDatabaseEnvironment > *  pOptionalParent,
  u_int32_t                               Flags 
  ) 
  : 
  m_pOptionalParent( pOptionalParent ), 
  m_pDbTxn( 0 )
{ 
  DbTxn *  pOptionalParentDbTxn = 0; 
  if ( m_pOptionalParent ) 
  { 
    pOptionalParentDbTxn = m_pOptionalParent->GetDbTxn(); 
  } 
  // We're using the C++ API so this throws if it fails.
  TBerkeley DBEnv::Instance()->txn_begin 
    ( 
    pOptionalParentDbTxn, 
    & m_pDbTxn, 
    TransactionFlags 
    ); 
} 
template< class TDatabaseEnvironment > 
CTransaction< TDatabaseEnvironment >::~CTransaction 
{ 
  try 
  { 
    // Call abort if not already called commit or abort. 
    if ( m_pDbTxn ) 
    {
      m_pDbTxn->abort(); 
    } 
  } 
  catch ( ... ) 
  { 
    // All destructors must be no-throw. 
  } 
} 
template< class CBerkeley DBEnv > 
void CTransaction<CBerkeley DBEnv>::Commit( u_int32_t CommitFlags ) 
{ 
  AssertPreCondition( "Not already commited or aborted", m_pDbTxn ); 
  // commit may throw but we are never allowed to use the DbTxn again.
  DbTxn *  pDbTxn = m_pDbTxn; 
  m_pDbTxn = 0;
  pDbTxn->commit( CommitFlags ); 
} 
template< class TDatabaseEnvironment > 
void CTransaction< TDatabaseEnvironment >::Abort() 
{ 
  AssertPreCondition( "Not already commited or aborted", m_pDbTxn ); 
  // abort may throw but we are never allowed to use the DbTxn again.
  DbTxn *  pDbTxn = m_pDbTxn; 
  m_pDbTxn = 0;
  pDbTxn->abort(); 
}