Thanks both of you.
I believe I have to use a reference counted class. The problem with
the above scenario was that I was using class variables for DbPtr
class which get duplicated before returning and thus committing both
copies. Here is the code that does the trick. DbBasePtr class is only
a single copy and keeps track commit status. If the copy is already
committed, second commit will simply be ignored.
I have another question. In my DbAutoPtr<T> class below, which
operator gets called for the rvalue operand, a->? Is there an implicit
or elegant (without creating or typecasting to a const object) way of
"const T& operator->( ) const" version to be called as the rvalue is
not being modified?
struct C {
int x;
};
struct A {
int y;
};
DbStore db;
DbAutoPtr< C> p(db, 0, sizeof( C ) );
DbAutoPtr< A > a( db, 0, sizeof(A) );
p->x = a->y;
===================
// DbAutPtr.h - auto pinter
#ifndef _DBAUTPTR_H_
#define _DBAUTPTR_H_
#include "syTypes.h"
#include "DbDefs.h"
#include "DbBasPtr.h"
#include "DbRefCnt.h"
class DbStore;
//////////////////////////////////////////////////////////////////////////
// DbAutoPtr< T > class
//////////////////////////////////////////////////////////////////////////
template< class T >
class DbAutoPtr {
public:
DbAutoPtr( );
DbAutoPtr( DbStore& rStore, fsize_type nAdr );
DbAutoPtr( DbStore& rStore, fsize_type nAdr, size_type nSize );
~DbAutoPtr( );
// Operators
T* operator->( );
const T* operator->( ) const;
DbAutoPtr< T >& operator=( const DbBasePtr& rP );
T& operator*( );
const T& operator*( ) const;
bool isNull( ) const;
fsize_type address( );
fsize_type address( ) const;
size_type size( ) const;
void setAddress( fsize_type nAdr );
void setSize( size_type nSize );
bool loadData( );
bool writeData( );
const DbBasePtr * basePtr( ) const;
// protected:
const T * pointer( ) const;
T * pointer( );
protected:
DbRefCount< DbBasePtr > _oData; // Object data
};
//////////////////////////////////////////////////////////////////////////
template<class T>
inline DbAutoPtr<T>:
bAutoPtr( )
//////////////////////////////////////////////////////////////////////////
{
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline DbAutoPtr<T>:
bAutoPtr( DbStore& rStore, fsize_type nAdr )
//////////////////////////////////////////////////////////////////////////
{
_oData = DbBasePtr( rStore, nAdr, sizeof( T ) );
_oData->loadData( );
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline DbAutoPtr<T>:
bAutoPtr( DbStore& rStore, fsize_type nAdr,
size_type nSize )
//////////////////////////////////////////////////////////////////////////
{
_oData = DbBasePtr( rStore, nAdr, nSize );
_oData->loadData( );
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline DbAutoPtr<T>::~DbAutoPtr( )
//////////////////////////////////////////////////////////////////////////
{
if( !_oData.isNull() )
_oData->writeData( T::Clsid() );
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline DbAutoPtr< T >& DbAutoPtr<T>:
perator=( const DbBasePtr& rP )
//////////////////////////////////////////////////////////////////////////
{
if( _oData.isNull() ) {
_oData = rP;
_oData->loadData( );
}
return *this;
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline const DbBasePtr * DbAutoPtr<T>::basePtr( ) const
//////////////////////////////////////////////////////////////////////////
{
return _oData.pointer();
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline T* DbAutoPtr<T>:
ointer( )
//////////////////////////////////////////////////////////////////////////
{
return (T*) _oData.pointer()->dataPointer();
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline const T* DbAutoPtr<T>:
ointer( ) const
//////////////////////////////////////////////////////////////////////////
{
return (const T*) _oData.pointer()->dataPointer();
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline const T* DbAutoPtr<T>:
perator->() const
//////////////////////////////////////////////////////////////////////////
{
return (const T*) pointer( );
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline T* DbAutoPtr<T>:
perator->()
//////////////////////////////////////////////////////////////////////////
{
return (T*) pointer();
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline const T& DbAutoPtr<T>:
perator*() const
//////////////////////////////////////////////////////////////////////////
{
V_ASSERT( pointer( ) );
return *((const T*) pointer( ));
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline T& DbAutoPtr<T>:
perator*()
//////////////////////////////////////////////////////////////////////////
{
V_ASSERT( pointer( ) );
return *((T*) pointer( ));
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline bool DbAutoPtr<T>::isNull( ) const
//////////////////////////////////////////////////////////////////////////
{
return _oData.isNull( ) || (0 == _oData->size( ) );
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline fsize_type DbAutoPtr<T>::address( ) const
//////////////////////////////////////////////////////////////////////////
{
return _oData->address( );
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline size_type DbAutoPtr<T>::size( ) const
//////////////////////////////////////////////////////////////////////////
{
return _oData->size( );
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline fsize_type DbAutoPtr<T>::address( )
//////////////////////////////////////////////////////////////////////////
{
return _oData->address( T::Clsid() );
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline void DbAutoPtr<T>::setAddress( fsize_type nAdr )
//////////////////////////////////////////////////////////////////////////
{
_oData->setAddress( nAdr );
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline void DbAutoPtr<T>::setSize( size_type nSize )
//////////////////////////////////////////////////////////////////////////
{
_oData->setSize( nSize );
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline bool DbAutoPtr<T>::loadData( )
//////////////////////////////////////////////////////////////////////////
{
return _oData->loadData( );
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline bool DbAutoPtr<T>::writeData( )
//////////////////////////////////////////////////////////////////////////
{
return _oData->writeData( T::Clsid() );
}
#endif
==========
// DbRefCount.h - compact reference counted class
#ifndef _REFCOUNT_H_
#define _REFCOUNT_H_
#include <stdlib.h>
#include "syTypes.h"
///////////////////////////////////////////////////////////////////////////////
// DbRefCount class
///////////////////////////////////////////////////////////////////////////////
template< class T >
class DbRefCount {
public:
DbRefCount( );
DbRefCount( const T& t );
DbRefCount( const DbRefCount& rPtr );
~DbRefCount( );
T* operator->( );
const T* operator->( ) const;
T& operator*( );
const T& operator*( ) const;
DbRefCount& operator=( const T& t );
DbRefCount& operator=( const DbRefCount& rPtr );
bool operator==( const DbRefCount& rPtr ) const;
bool isNull( ) const;
// protected:
const T * pointer( ) const;
T * pointer( );
void copyFrom( const DbRefCount& rSrc);
void release( );
void * alloc( size_t nSize );
protected:
int * _pPtr;
};
///////////////////////////////////////////////////////////////////////////////
template< class T >
inline DbRefCount< T >:
bRefCount( ) : _pPtr( NULLPTR )
///////////////////////////////////////////////////////////////////////////////
{
}
///////////////////////////////////////////////////////////////////////////////
template< class T >
inline DbRefCount< T >:
bRefCount( const T& t ) : _pPtr( NULLPTR )
///////////////////////////////////////////////////////////////////////////////
{
T * p = new( alloc( sizeof(T) ) ) T( t );
}
///////////////////////////////////////////////////////////////////////////////
template< class T >
inline DbRefCount< T >:
bRefCount( const DbRefCount< T >& rPtr )
///////////////////////////////////////////////////////////////////////////////
{
copyFrom( rPtr );
}
///////////////////////////////////////////////////////////////////////////////
template< class T >
inline DbRefCount< T >::~DbRefCount( )
///////////////////////////////////////////////////////////////////////////////
{
release( );
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline const T* DbRefCount<T>:
perator->() const
//////////////////////////////////////////////////////////////////////////
{
return pointer( );
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline T* DbRefCount<T>:
perator->()
//////////////////////////////////////////////////////////////////////////
{
return pointer( );
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline const T& DbRefCount<T>:
perator*() const
//////////////////////////////////////////////////////////////////////////
{
V_ASSERT( pointer( ) );
return *pointer( );
}
//////////////////////////////////////////////////////////////////////////
template<class T>
inline T& DbRefCount<T>:
perator*()
//////////////////////////////////////////////////////////////////////////
{
V_ASSERT( pointer( ) );
return *pointer( );
}
///////////////////////////////////////////////////////////////////////////////
template<class T>
inline const T * DbRefCount< T >:
ointer( ) const
///////////////////////////////////////////////////////////////////////////////
{
V_ASSERT( _pPtr );
return (const T *) (_pPtr + 1);
}
///////////////////////////////////////////////////////////////////////////////
template<class T>
inline T * DbRefCount< T >:
ointer( )
///////////////////////////////////////////////////////////////////////////////
{
return _pPtr ? (T *) (_pPtr + 1) : NULLPTR;
}
///////////////////////////////////////////////////////////////////////////////
template<class T>
inline DbRefCount< T >& DbRefCount< T >:
perator =( const T& t )
///////////////////////////////////////////////////////////////////////////////
{
if( NULLPTR == _pPtr )
new( alloc( sizeof(T) ) ) T( t );
return *this;
}
///////////////////////////////////////////////////////////////////////////////
template<class T>
inline DbRefCount< T >& DbRefCount< T >:
perator=( const DbRefCount<
T >& rPtr )
///////////////////////////////////////////////////////////////////////////////
{
if( &rPtr != this ) {
release( );
copyFrom( rPtr );
}
return *this;
}
///////////////////////////////////////////////////////////////////////////////
template<class T>
inline bool DbRefCount< T >:
perator==( const DbRefCount< T >& rRhs )
const
///////////////////////////////////////////////////////////////////////////////
{
return _pPtr == rRhs._pPtr;
}
///////////////////////////////////////////////////////////////////////////////
template<class T>
inline bool DbRefCount< T >::isNull( ) const
///////////////////////////////////////////////////////////////////////////////
{
return _pPtr == NULLPTR;
}
///////////////////////////////////////////////////////////////////////////////
template<class T>
inline void DbRefCount< T >::release( )
///////////////////////////////////////////////////////////////////////////////
{
if( _pPtr ) {
(*_pPtr)--;
if( *_pPtr == 0 ) {
T * tp = pointer( );
tp->~T( );
::free( _pPtr );
_pPtr = NULLPTR;
}
}
}
///////////////////////////////////////////////////////////////////////////////
template<class T>
inline void DbRefCount< T >::copyFrom( const DbRefCount< T >& rSrc )
///////////////////////////////////////////////////////////////////////////////
{
_pPtr = rSrc._pPtr;
if( _pPtr ) (*_pPtr)++;
}
///////////////////////////////////////////////////////////////////////////////
template<class T>
inline void * DbRefCount< T >::alloc( size_t nSize )
///////////////////////////////////////////////////////////////////////////////
{
int * pPtr = (int *) ::realloc( _pPtr, nSize + sizeof(int) );
if( NULLPTR == _pPtr ) {
*pPtr = 1;
}
_pPtr = pPtr;
return _pPtr + 1;
}
#endif
=======
// DbBasPtr.h
#ifndef _DBBASPTR_H_
#define _DBBASPTR_H_
#include "syTypes.h"
#include "DbDefs.h"
#include "DbObjRef.h"
class DbStore;
///////////////////////////////////////////////////////////////////////////////
// DbBasePtr
///////////////////////////////////////////////////////////////////////////////
class DbBasePtr : public DbObjRef {
public:
DbBasePtr( DbStore& rStore, fsize_type nAdr, size_type nSize );
~DbBasePtr( );
const void * dataPointer( ) const;
void * dataPointer( );
fsize_type address( clsid_type nClsid );
fsize_type address( ) const;
// protected:
bool loadData( );
bool writeData( clsid_type nClsid );
void * alloc( size_type nSize );
protected:
DbStore * _pStore;
void * _pData; // Object data
};
///////////////////////////////////////////////////////////////////////////////
inline DbBasePtr:
bBasePtr( DbStore& rStore, fsize_type nAdr,
size_type nSize )
: DbObjRef( nAdr, nSize ), _pStore( &rStore ),
_pData( NULLPTR )
///////////////////////////////////////////////////////////////////////////////
{
}
///////////////////////////////////////////////////////////////////////////////
inline DbBasePtr::~DbBasePtr( )
///////////////////////////////////////////////////////////////////////////////
{
}
///////////////////////////////////////////////////////////////////////////////
inline const void * DbBasePtr::dataPointer( ) const
///////////////////////////////////////////////////////////////////////////////
{
return _pData;
}
///////////////////////////////////////////////////////////////////////////////
inline void * DbBasePtr::dataPointer( )
///////////////////////////////////////////////////////////////////////////////
{
setDirty( );
return _pData;
}
//////////////////////////////////////////////////////////////////////////
inline fsize_type DbBasePtr::address( ) const
//////////////////////////////////////////////////////////////////////////
{
return DbObjRef::address( );
}
//////////////////////////////////////////////////////////////////////////
inline fsize_type DbBasePtr::address( clsid_type nClsid )
//////////////////////////////////////////////////////////////////////////
{
writeData( nClsid );
return DbObjRef::address( );
}
#endif