#ifndef _SMARTPTR_H_
#define _SMARTPTR_H_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
/*************************************************************************
FILE : SmartPtr.h
Date : 20 December 1998
Author : Stefan Tchekanov (stefant@iname.com)
Description: The template class SmartPtr performs Reference Counting
Garbage Collection and/or Object Level Thread Synchronization.
Classes : SmartPtr - The SmartPtr class
RefCountPtr - Reference Counting Garbage Collection
SyncPtr - Synchronized access without Reference Counting Garbage Collection
SyncRefCountPtr - Synchronized access with Reference Counting Garbage Collection
SmartPtrBase - The base of all above classes. Used as a common base so
an assignment between different pointers is able.
For examples how to use these classes look at the end
of this file.
Implementation classes that SHOULD NEVER be used directly.
CRefCountRep
CSyncAccessRep
CSyncRefCountRep
CSyncAccess
Copyright notice:
Written by Stefan Tchekanov (stefant@iname.com)
Copyright(c) 1998,1999,2000
This code may be used in compiled form in any way you desire. This
file may be redistributed unmodified by any means PROVIDING it is
not sold for profit without the authors written consent, and
providing that this notice and the authors name is included. If
the source code in this file is used in any commercial application
then a simple email would be nice.
This file is provided "as is" with no expressed or implied warranty.
The author accepts no liability if it causes any damage to your
computer.
*************************************************************************/
/* # Revisions # */
/*************************************************************************
REVISION ON 7.January.2000 14:31:34 By Stefan Tchekanov
Comments : SmartPtr objects can point to objects of other types
not only to objects of their type.
*************************************************************************/
/*************************************************************************
REVISION ON 09 April 1999 11:24:38 By Stefan Tchekanov
Comments : SmartPtr objects now have size of a real pointer, Which
means that passing a SmartPtr as a function parameter is
as efficient as passing an int or a pointer.
*************************************************************************/
/////////////////////////////////////////////////////////////////////////////
// If you wrap a non-class with the SmartPtr class, you will receive
// this warning. i.e. int, short, etc...
// It is a warning you may ignore.
#pragma warning( disable : 4284 )
//
// This warning is generated when compiling in debug mode.
// Debug symbols cannot be longer than 255 but when using templates
// it is usual to have debug symbols longer tahn 255.
// You may ignore this warning.
#pragma warning( disable : 4786 )
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Representation class just for reference counting
/////////////////////////////////////////////////////////////////////////////
template<class T>
class CRefCountRep {
// Constructors and destructor
public:
CRefCountRep( const T* ptr );
~CRefCountRep();
// Operations
public:
long incrRefCount();
long decrRefCount();
T* getPointer() const;
T* getRealPointer() const;
bool isNull() const;
// Implementation
private:
T* m_pRealPtr;
long m_counter;
};
/////////////////////////////////////////////////////////////////////////////
template<class T>
CRefCountRep<T>::CRefCountRep( const T* ptr )
: m_pRealPtr( (T*)ptr ), m_counter( 0 ) {
}
template<class T>
CRefCountRep<T>::~CRefCountRep() {
ASSERT( m_counter <= 0 );
delete m_pRealPtr;
}
template<class T>
long CRefCountRep<T>::incrRefCount() {
return ::InterlockedIncrement( &m_counter );
}
template<class T>
long CRefCountRep<T>::decrRefCount() {
return ::InterlockedDecrement( &m_counter );
}
template<class T>
T* CRefCountRep<T>::getPointer() const {
return m_pRealPtr;
}
template<class T>
T* CRefCountRep<T>::getRealPointer() const {
return m_pRealPtr;
}
template<class T>
bool CRefCountRep<T>::isNull() const {
return m_pRealPtr == NULL;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
template <class T> class CSyncAccess;
/////////////////////////////////////////////////////////////////////////////
// Representation class just for thread synchronization
/////////////////////////////////////////////////////////////////////////////
template<class T>
class CSyncAccessRep {
// Constructors and destructor
public:
CSyncAccessRep( const T* ptr );
~CSyncAccessRep();
typedef CSyncAccess<T> ACCESS;
// Operations
public:
long incrRefCount();
long decrRefCount();
ACCESS getPointer() const;
T* getRealPointer() const;
bool isNull() const;
void acquireAccess();
void releaseAccess();
// Implementation
protected:
T* m_pRealPtr;
long m_counter;
CRITICAL_SECTION m_CriticalSection;
};
/////////////////////////////////////////////////////////////////////////////
template<class T>
CSyncAccessRep<T>::CSyncAccessRep( const T* ptr )
: m_pRealPtr( (T*)ptr ), m_counter( 0 ) {
::InitializeCriticalSection( &m_CriticalSection );
}
template<class T>
CSyncAccessRep<T>::~CSyncAccessRep() {
ASSERT( m_counter <= 0 );
::DeleteCriticalSection( &m_CriticalSection );
}
template<class T>
long CSyncAccessRep<T>::incrRefCount() {
return ::InterlockedIncrement( &m_counter );
}
template<class T>
long CSyncAccessRep<T>::decrRefCount() {
return ::InterlockedDecrement( &m_counter );
}
template<class T>
CSyncAccessRep<T>::ACCESS CSyncAccessRep<T>::getPointer() const {
return this; // Object of type ACCESS (CSyncAccess<T>)
// will be automatically created on the stack
}
template<class T>
T* CSyncAccessRep<T>::getRealPointer() const {
return m_pRealPtr;
}
template<class T>
bool CSyncAccessRep<T>::isNull() const {
return m_pRealPtr == NULL;
}
template<class T>
void CSyncAccessRep<T>::acquireAccess() {
::EnterCriticalSection( &m_CriticalSection );
}
template<class T>
void CSyncAccessRep<T>::releaseAccess() {
::LeaveCriticalSection( &m_CriticalSection );
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Representation class for Reference Counting AND Thread Synchronization
/////////////////////////////////////////////////////////////////////////////
template<class T>
class CSyncRefCountRep : public CSyncAccessRep<T> {
// Constructors and destructor
public:
CSyncRefCountRep( const T* ptr );
~CSyncRefCountRep();
};
/////////////////////////////////////////////////////////////////////////////
template<class T>
CSyncRefCountRep<T>::CSyncRefCountRep( const T* ptr )
: CSyncAccessRep<T>( ptr ) {
}
template<class T>
CSyncRefCountRep<T>::~CSyncRefCountRep() {
ASSERT( m_counter <= 0 );
delete m_pRealPtr; // This is the only change needed to make in
// CSyncRefCountRep<T> class to collect the garbage and
// in the same time to do Object Level Thread Synchronization
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
// The SyncAccess class. It is used as an intermediary to achieve
// Object Level Thread Synchronization
//
/////////////////////////////////////////////////////////////////////////////
template <class T>
class CSyncAccess {
// Internally used data type
private:
typedef CSyncAccessRep<T> REP;
// Constructors and destructors
public:
// Copy constructor
CSyncAccess( const CSyncAccess& that );
CSyncAccess( const REP* rep );
~CSyncAccess();
// Operators
public:
T* operator -> ();
// Implementation
private:
REP* m_rep;
bool m_acquired;
};
/////////////////////////////////////////////////////////////////////////////
template <class T>
CSyncAccess<T>::CSyncAccess( const REP* rep )
: m_rep( (REP*)rep ), m_acquired( false ) {
}
template <class T>
CSyncAccess<T>::CSyncAccess( const CSyncAccess<REP>& that )
: m_rep( that.m_rep ), m_acquired( false ) {
}
template <class T>
CSyncAccess<T>::~CSyncAccess() {
if( m_acquired ) {
m_rep->releaseAccess();
}
}
template <class T>
T* CSyncAccess<T>::operator -> () {
// This is checked by SmartPtr<T>::operator -> () too
ASSERT( (m_rep != NULL) && (! m_rep->isNull()) );
if( ! m_acquired ) {
m_rep->acquireAccess();
m_acquired = true;
}
return m_rep->getRealPointer();
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// The SmartPtr class
/////////////////////////////////////////////////////////////////////////////
class SmartPtrBase {
public:
SmartPtrBase() : m_rep( NULL )
{};
void* m_rep;
};
/////////////////////////////////////////////////////////////////////////////
template<class T, class REP, class ACCESS = T*>
class SmartPtr : public SmartPtrBase {
// Constructors and destructor
public:
// Default constructor and destructor
SmartPtr();
~SmartPtr();
// Copy constructor
SmartPtr( const SmartPtr& ptr );
// Other constructors
SmartPtr( const T* ptr );
SmartPtr( const SmartPtrBase& ptr );
// Assignment Operators
public:
SmartPtr& operator = ( const SmartPtr& ptr );
SmartPtr& operator = ( const T* ptr );
SmartPtr& operator = ( const SmartPtrBase& ptr );
// Operators
public:
ACCESS operator -> ();
T& operator * ();
// Casting operator
operator T* ();
// Comparison Operators
bool operator == ( const SmartPtrBase& ptr );
bool operator == ( const T* ptr );
bool operator != ( const SmartPtrBase& ptr );
bool operator != ( const T* ptr );
// Attributes
public:
bool IsNull() const;
long GetRefCount() const;
REP* GetRepPtr() const;
// Helper methods
protected:
void CopyFrom( const SmartPtrBase& ptr );
void CopyFrom( const T* ptr );
// Implementation
private:
void IncrRefCount();
void DecrRefCount();
};
/////////////////////////////////////////////////////////////////////////////
template<class T, class REP, class ACCESS>
SmartPtr<T,REP,ACCESS>::SmartPtr()
{
}
template<class T, class REP, class ACCESS>
SmartPtr<T,REP,ACCESS>::~SmartPtr()
{
DecrRefCount();
}
template<class T, class REP, class ACCESS>
SmartPtr<T,REP,ACCESS>::SmartPtr( const SmartPtr& ptr )
{
CopyFrom( ptr );
}
template<class T, class REP, class ACCESS>
SmartPtr<T,REP,ACCESS>::SmartPtr( const T* ptr )
{
CopyFrom( ptr );
}
template<class T, class REP, class ACCESS>
SmartPtr<T,REP,ACCESS>::SmartPtr( const SmartPtrBase& ptr )
{
CopyFrom( ptr );
}
template<class T, class REP, class ACCESS>
void SmartPtr<T,REP,ACCESS>::CopyFrom( const SmartPtrBase& ptr )
{
if( m_rep != ptr.m_rep ) {
DecrRefCount();
m_rep = ptr.m_rep;
IncrRefCount();
}
}
template<class T, class REP, class ACCESS>
void SmartPtr<T,REP,ACCESS>::CopyFrom( const T* ptr )
{
DecrRefCount();
m_rep = (ptr != NULL) ? new REP( ptr ) : NULL;
IncrRefCount();
}
template<class T, class REP, class ACCESS>
SmartPtr<T,REP,ACCESS>& SmartPtr<T,REP,ACCESS>::operator = ( const SmartPtr& ptr ) {
CopyFrom( ptr );
return *this;
}
template<class T, class REP, class ACCESS>
SmartPtr<T,REP,ACCESS>& SmartPtr<T,REP,ACCESS>::operator = ( const T* ptr ) {
CopyFrom( ptr );
return *this;
}
template<class T, class REP, class ACCESS>
SmartPtr<T,REP,ACCESS>& SmartPtr<T,REP,ACCESS>::operator = ( const SmartPtrBase& ptr ) {
CopyFrom( ptr );
return *this;
}
template<class T, class REP, class ACCESS>
ACCESS SmartPtr<T,REP,ACCESS>::operator -> () {
ASSERT( ! IsNull() );
return GetRepPtr()->getPointer();
}
template<class T, class REP, class ACCESS>
T& SmartPtr<T,REP,ACCESS>::operator * () {
ASSERT( ! IsNull() );
return *(GetRepPtr()->getRealPointer());
}
template<class T, class REP, class ACCESS>
SmartPtr<T,REP,ACCESS>::operator T* () {
return ( IsNull() ) ? NULL : GetRepPtr()->getRealPointer();
}
template<class T, class REP, class ACCESS>
bool SmartPtr<T,REP,ACCESS>::operator == ( const SmartPtrBase& ptr ) {
return m_rep == ptr.m_rep;
}
template<class T, class REP, class ACCESS>
bool SmartPtr<T,REP,ACCESS>::operator == ( const T* ptr ) {
if( ! IsNull() ) {
return GetRepPtr()->getRealPointer() == ptr;
}
return ptr == NULL;
}
template<class T, class REP, class ACCESS>
bool SmartPtr<T,REP,ACCESS>::operator != ( const SmartPtrBase& ptr ) {
return m_rep != ptr.m_rep;
}
template<class T, class REP, class ACCESS>
bool SmartPtr<T,REP,ACCESS>::operator != ( const T* ptr ) {
return ! (operator ==( ptr ));
}
template<class T, class REP, class ACCESS>
bool SmartPtr<T,REP,ACCESS>::IsNull() const {
return m_rep == NULL;
}
template<class T, class REP, class ACCESS>
long SmartPtr<T,REP,ACCESS>::GetRefCount() const {
ASSERT( ! IsNull() );
return GetRepPtr()->m_counter;
}
template<class T, class REP, class ACCESS>
REP* SmartPtr<T,REP,ACCESS>::GetRepPtr() const {
return (REP*)m_rep;
}
template<class T, class REP, class ACCESS>
void SmartPtr<T,REP,ACCESS>::IncrRefCount() {
if( ! IsNull() ) {
GetRepPtr()->incrRefCount();
}
}
template<class T, class REP, class ACCESS>
void SmartPtr<T,REP,ACCESS>::DecrRefCount() {
if( ! IsNull() ) {
if( GetRepPtr()->decrRefCount() <= 0 ) {
REP* rep = (REP*)m_rep;
delete rep;
}
m_rep = NULL;
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
// Helper classes for easier use of the SmartPtr class
//
/////////////////////////////////////////////////////////////////////////////
template<class T, class REP = CRefCountRep<T>, class ACCESS = T*>
class RefCountPtr : public SmartPtr<T, REP, ACCESS> {
// Constructors and destructor
public:
// Default constructor and destructor
RefCountPtr() {};
~RefCountPtr() {};
// Copy constructor
RefCountPtr( const RefCountPtr& ptr )
: SmartPtr<T,REP,ACCESS>( ptr )
{};
RefCountPtr( const SmartPtrBase& ptr )
: SmartPtr<T,REP,ACCESS>( ptr )
{};
RefCountPtr( const T* ptr )
: SmartPtr<T,REP,ACCESS>( ptr )
{};
// Assignment Operators
public:
RefCountPtr& operator = ( const RefCountPtr& ptr ) {
CopyFrom( ptr );
return *this;
}
RefCountPtr& operator = ( const T* ptr ) {
CopyFrom( ptr );
return *this;
}
RefCountPtr& operator = ( const SmartPtrBase& ptr ) {
CopyFrom( ptr );
return *this;
}
};
/////////////////////////////////////////////////////////////////////////////
template<class T, class REP = CSyncAccessRep<T>, class ACCESS = CSyncAccess<T> >
class SyncPtr : public SmartPtr<T, REP, ACCESS> {
// Constructors and destructor
public:
// Default constructor and destructor
SyncPtr() {};
~SyncPtr() {};
// Copy constructor
SyncPtr( const SyncPtr& ptr )
: SmartPtr<T,REP,ACCESS>( ptr )
{};
SyncPtr( const SmartPtrBase& ptr )
: SmartPtr<T,REP,ACCESS>( ptr )
{};
SyncPtr( const T* ptr )
: SmartPtr<T,REP,ACCESS>( ptr )
{};
// Assignment Operators
public:
SyncPtr& operator = ( const SyncPtr& ptr ) {
CopyFrom( ptr );
return *this;
}
SyncPtr& operator = ( const T* ptr ) {
CopyFrom( ptr );
return *this;
}
SyncPtr& operator = ( const SmartPtrBase& ptr ) {
CopyFrom( ptr );
return *this;
}
};
/////////////////////////////////////////////////////////////////////////////
template<class T, class REP = CSyncRefCountRep<T>, class ACCESS = CSyncAccess<T> >
class SyncRefCountPtr : public SmartPtr<T, REP, ACCESS> {
// Constructors and destructor
public:
// Default constructor and destructor
SyncRefCountPtr() {};
~SyncRefCountPtr() {};
// Copy constructor
SyncRefCountPtr( const SyncRefCountPtr& ptr )
: SmartPtr<T,REP,ACCESS>( ptr )
{};
SyncRefCountPtr( const SmartPtrBase& ptr )
: SmartPtr<T,REP,ACCESS>( ptr )
{};
SyncRefCountPtr( const T* ptr )
: SmartPtr<T,REP,ACCESS>( ptr )
{};
// Assignment Operators
public:
SyncRefCountPtr& operator = ( const SyncRefCountPtr& ptr ) {
CopyFrom( ptr );
return *this;
}
SyncRefCountPtr& operator = ( const T* ptr ) {
CopyFrom( ptr );
return *this;
}
SyncRefCountPtr& operator = ( const SmartPtrBase& ptr ) {
CopyFrom( ptr );
return *this;
}
};
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
// Examples on how to use these classes.
//
// There are 3 cases:
// 1. Reference Counting
// 2. Object Level Thread Synchronization
// 3. Object Level Thread Synchronization AND Reference Counting
//
/*
Let's have a class CSomething
1. Reference Counting on CSomething
------------------------------------
class CSomething {
CSomething();
~CSomething();
.....
void do();
};
typedef RefCountPtr<CSomething> LPSOMETHING;
void TestFunct() {
LPSOMETHING p1 = new CSomething;
LPSOMETHING p2 = p1;
if( p1 == NULL ) {
....
}
p2->do();
p1 = NULL;
} // Here the object pointed by p2 WILL BE destroyed automatically
/////////////////////////////////////////////////////////////////////////////
2. Object Level Thread Synchronization for objects of CSomething
---------------------------------------------------------
class CSomething {
CSomething();
~CSomething();
.....
void do();
};
typedef SyncPtr<CSomething> LPSOMETHING;
void TestFunct() {
LPSOMETHING p1 = new CSomething;
LPSOMETHING p2 = p1;
if( p1.IsNULL() ) {
....
}
StartThread( p1 );
p2->do(); // Synchronized with the other thread
p1 = NULL;
} // Here the object pointed by p2 will NOT be destroyed automatically
void ThreadFunc( LPSOMETHING p ) {
p->do(); // Synchronized with the other thread
}// Here the object pointed by p will NOT be destroyed automatically
/////////////////////////////////////////////////////////////////////////////
3. Object Level Thread Synchronization and Reference Counting
for objects of CSomething
---------------------------------------------------------
class CSomething {
CSomething();
~CSomething();
.....
void do();
};
typedef SyncRefCountPtr<CSomething> LPSOMETHING;
void TestFunct() {
LPSOMETHING p1 = new CSomething;
LPSOMETHING p2 = p1;
if( p1.IsNULL() ) {
....
}
StartThread( p1 );
p2->do(); // Synchronized with the other thread
p1 = NULL;
} // Here the object pointed by p2 WILL BE destroyed automatically
// if p in ThreadFunc has already released the object
void ThreadFunc( LPSOMETHING p ) {
p->do(); // Synchronized with the other thread
}// Here the object pointed by p WILL BE destroyed automatically
// if p2 in TestFunc has already released the object
/////////////////////////////////////////////////////////////////////////////
WARNING: Don't use a code like this
CSomething* ptr = new CSomething(); // A real pointer
LPSOMETHING p1 = ptr;
LPSOMETHING p2 = ptr; // This will lead to 2 (two)
// representation objects.
// So you will not have nor proper
// grabage collection nor proper
// thread synchronization
if( p1 != p2 ) { // The comparison will say these
ASSERT( FALSE ); // point to different objects
} // even you think it is the same
/////////////////////////////////////////////////////////////////////////////
sizeof( CRITICAL_SECTION ) 24
sizeof( CRefCountRep ) 8
sizeof( CSyncAccessRep ) 32
sizeof( CSyncRefCountRep ) 32
sizeof( CSyncAccess ) 8
sizeof( SmartPtr ) 4
sizeof( CSomething* ) 4
sizeof( int ) 4
*/
#endif // _SMARTPTR_H_