Click here to Skip to main content
15,886,578 members
Articles / Programming Languages / C++

A Smart Pointer Capable of Object Level Thread Synchronization and Reference Counting Garbage Collection

Rate me:
Please Sign up or sign in to vote.
4.89/5 (19 votes)
12 Jan 20008 min read 177.2K   1.8K   65  
A smart pointer wrapper class
#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_

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior) Brosix
Bulgaria Bulgaria
Stefan does programming since his early ages more than 30 years ago. Later he began programming at his work and now he is very happy to work his hobby. He owns a Master's degree in Computer Science.

During his professional career, Stefan has worked with many technologies. His programming experience includes C/C++, Java, C#, PHP, JavaScript, MFC, ATL, ASP, ASP.NET, TCP/IP, SQL. He has worked with different operating systems: Windows, Linux, Mac OS X, iOS, Android, Solaris, FreeBSD, NetBSD and QNX.

Currently his professional interests are in building large scale distributed systems that operate over the Internet. This involves building server components as well as developing system level software.

More information about his current work can be found here: brosix.com - Enterprise Instant Messaging


Stefan is based in Plovdiv, Bulgaria. It is a very nice and peaceful place combined with an enjoyable weather.

Stefan has a wife and 2 children. He likes in his spear time to travel with his family to see new and interesting places.

Comments and Discussions