Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

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

, 12 Jan 2000
A smart pointer wrapper class
smartptr.zip
smartptr_demo.zip
SmartPtrDemo.dsp
SmartPtrDemo.dsw
<html>

<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<meta NAME="Author" CONTENT="Stefan Tchekanov">
<meta Name="description" Content="Source codes with MFC">
<meta Name="keywords" Content="SOURCE CODE MFC">
<title>A Smart Pointer Capable of Object Level Thread Synchronization and Reference
Counting Garbage Collection</title>
</head>

<body bgcolor="#ffffff" text="#000000">

<h3 align="center"><font COLOR="#000000">A Smart Pointer Capable of Object Level Thread
Synchronization and Reference Counting Garbage Collection</font></h3>

<hr>
<!-- Author and contact details -->

<p>This article was contributed by <a href="mailto:stefant@iname.com">Stefan Tchekanov</a>.

<ul>
  <li><a href="##whats_new">What is new </li>
  <li></a><a href="##intro">Introduction</a> </li>
  <li><a href="##examples">Examples of how to use SmartPtr</a> </li>
  <li><a href="##how_works">How does SmartPtr work?</a> </li>
</ul>

<p>&nbsp;</p>

<p><a name="#whats_new"></a><big><strong>What is new</strong></big> 

<ul>
  <li>SmartPtr objects can accept different pointer types - <a href="##dif_ptr_types">details</a>
  </li>
  <li>Passing a SmartPtr object as function parameter or function result is as efficient as
    passing an integer value or regular pointer - <a href="##efficency">details</a>.</li>
</ul>

<p>&nbsp;</p>

<p><a name="#intro"></a><big><strong>Introduction</strong></big></p>

<p>The SmartPtr class is a generic wrapper that encapsulates pointers. It keeps track of
the total number of reference counts and performs garbage collection when the pointed
object is no more referenced by any &quot;pointer&quot;. In addition SmartPtr can do
Object Level Thread Synchronization for pointed objects. This means that calling the
members of the pointed object is enclosed in Windows critical section and only one thread
at a time can use the object. </p>

<p>SmartPtr stores reference counter and critical section in separate memory block - not
in the pointed object. This causes that you don't have to inherit your classes from
special base one to be able to use SmartPtr as a pointer. And one other think is that you
could use SmartPtr to point objects of scalar types - int, short, long, double .... </p>

<p>SmartPtr is implemented as a template class. Because it has three template parameters
it is annoying to specify all of them each time. This is the reason I have defined three
additional template classes inherited from SmartPtr with appropriate default template
parameters to get three diferent behaviours: 

<ul>
  <li><strong>Reference Counting Garbage Collection</strong> - SmartPtr will free dynamically
    allocated memory automatically. </li>
  <li><strong>Synchronized Access without Reference Counting Garbage Collection</strong> -
    SmartPtr will perform only Thread synchronization. You should free dynamically allocated
    memory in your own. </li>
  <li><strong>Synchronized Access with Reference Counting Garbage Collection</strong> -
    SmartPtr will perform thread synchronization and will free dynamically allocated memory
    for you.</li>
</ul>

<p>These are the classes: </p>

<table border="1" width="100%">
  <tr>
    <th width="23%" bgcolor="#800080"><font color="#ffffff">Class Name</font></th>
    <th width="77%" bgcolor="#800080"><font color="#ffffff">Description</font></th>
  </tr>
  <tr>
    <td width="23%" bgcolor="#e0e0e0"><strong>SmartPtrBase</strong></td>
    <td width="77%" bgcolor="#e0e0e0">The SmartPtrBase class is a non template base class for
    the SmartPtr class. It should never be used directly. SmartPtr uses it to perform
    appropriate type casting</td>
  </tr>
  <tr>
    <td width="23%" bgcolor="#e0e0e0"><strong>SmartPtr</strong></td>
    <td width="77%" bgcolor="#e0e0e0">The SmartPtr class is a template base class for the next
    classes</td>
  </tr>
  <tr>
    <td width="23%" bgcolor="#e0e0e0"><strong>RefCountPtr</strong></td>
    <td width="77%" bgcolor="#e0e0e0">Smart pointers that perform only Reference Counting
    Garbage Collection</td>
  </tr>
  <tr>
    <td width="23%" bgcolor="#e0e0e0"><strong>SyncPtr</strong></td>
    <td width="77%" bgcolor="#e0e0e0">Smart pointers that perform only Synchronized Access
    without Reference Counting Garbage Collection</td>
  </tr>
  <tr>
    <td width="23%" bgcolor="#e0e0e0"><strong>SyncRefCountPtr</strong></td>
    <td width="77%" bgcolor="#e0e0e0">Smart pointers that perform both Synchronized Access and
    Reference Counting Garbage Collection</td>
  </tr>
</table>

<p>All of these classes are equal in their implementation. The different behaviour is
achieved via different default template parameters.You could use any of these four classes
to get any of the three behaviours but then you should specify all parameters.<br>
<br>
The following classes are used inside the SmartPtr implementation and SHOULD NEVER be used
directly. 

<ul>
  <li>CRefCountRep </li>
  <li>CSyncAccessRep </li>
  <li>CSyncRefCountRep </li>
  <li>CSyncAccess </li>
</ul>

<p><a name="#examples"></a><big><strong>Examples of how to use SmartPtr</strong></big></p>

<p>You should include the file <font color="#800000">SmartPtr.h</font> in your project.</p>

<p>I usually include this line in my <font color="#800000">StdAfx.h</font> file.</p>

<pre><tt><font color="#990000">#include &quot;SmartPtr.h&quot;</font></tt></pre>

<p>&nbsp;</p>

<p>Let's have a class CSomething</p>
<strong>

<p>1. Reference Counting Garbage Collection on CSomething class</strong></p>

<pre><tt><font color="#990000">class	CSomething {
	CSomething();
	~CSomething();
.....	
	void	do();
};

typedef	RefCountPtr&lt;CSomething&gt;	LPSOMETHING;

	
void	TestFunct() {
	LPSOMETHING	p1 = new CSomething;
	LPSOMETHING	p2 = p1;

	if( p1 == NULL ) {
	....
	}

	p2-&gt;do();
	p1 = NULL;

}//	Here the object pointed by p2 WILL BE destroyed automatically
/////////////////////////////////////////////////////////////////////////////</font></tt></pre>

<p>&nbsp;</p>

<p><strong>2. Object Level Thread Synchronization for objects of CSomething</strong></p>

<pre><tt><font color="#990000">class	CSomething {
	CSomething();
	~CSomething();
.....	
	void	do();
};

typedef	SyncPtr<CSOMETHING>&lt;CSomething&gt;	LPSOMETHING;
	
void	TestFunct() {
	LPSOMETHING	p1 = new CSomething;
	LPSOMETHING	p2 = p1;

	if( p1.IsNull() ) {
	....
	}
	StartThread( p1 );

	p2-&gt;do();	//	Synchronized with the other thread
	p1 = NULL;

}	//	Here the object pointed by p2 will NOT be destroyed automatically

void	ThreadFunc( LPSOMETHING p ) {
	p-&gt;do();	//	Synchronized with the other thread
}//	Here the object pointed by p will NOT be destroyed automatically
/////////////////////////////////////////////////////////////////////////////</font></tt></pre>

<p>In this example you will get memory leaks, but the two threads will be synchronized
when trying to call object's members. It is your care to free dynamically allocated
memory.</p>

<p>&nbsp;</p>

<p><strong>3. Object Level Thread Synchronization and Reference Counting Garbage
Collection for objects of CSomething</strong></p>

<pre><tt><font color="#990000">class	CSomething {
	CSomething();
	~CSomething();
.....	
	void	do();
};

typedef	SyncRefCountPtr<CSOMETHING>&lt;CSomething&gt;	LPSOMETHING;
	
void	TestFunct() {
	LPSOMETHING	p1 = new CSomething;
	LPSOMETHING	p2 = p1;

	if( p1.IsNull() ) {
	....
	}
	StartThread( p1 );

	p2-&gt;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-&gt;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
/////////////////////////////////////////////////////////////////////////////</font></tt></pre>

<p>In this example you will not get memory leaks and the two threads will be synchronized
when trying to call object's members. You don't have to free dynamically allocated memory.
SmartPtr will do it for you.</p>

<p>&nbsp;</p>

<p><a name="#how_works"></a><big><strong>How does SmartPtr work?</strong></big></p>

<p>The definition of SmartPtr is:</p>

<pre><tt><font color="#990000">template&lt;class T, class REP=CRefCountRep&lt;T&gt;, class ACCESS = T*&gt;
class SmartPtr : public SmartPtrBase {
...........
};</font></tt></pre>

<p>Where <em>T</em> is the type of the pointed objects, <em>REP</em> is the representation
class used to handle the pointers and <em>ACCESS</em> is the class used to get thread safe
access to the underlying real pointer.</p>

<p>There is nothing interesting about Reference Counting Garbage Collection. It is a
standard implementation. The only interesting thing is that the reference counter and the
real pointer are stored in the representation object instead of the pointed object.</p>

<p>The more interesting thing is how Object Level Thread Synchronization works. Let's look
at the definition of SyncPtr class:</p>

<pre><tt><font color="#990000">template&lt;class T, class REP=CSyncAccessRep&lt;T&gt;, class ACCESS=CSyncAccess&lt;T&gt; &gt;
class SyncPtr {
...........
	ACCESS	operator -&gt; ();
};</font></tt></pre>

<p>Look at the reference operator. It returns object of type ACCESS, which by default is
of type CSyncAccess&lt;T&gt;. The trick is that if the reference operator returns
something different than a real pointer, the compiler calls the operator -&gt;() of the
returned object. If it returns again something different than a real pointer compiler
calls the returned object operator -&gt;(). And this continues till some reference
operator returns a real pointer like T*. Well, to get object level synchronization I use
this behaviour of the reference operator. I have defined a class CSyncAccess&lt;T&gt;:</p>

<pre><tt><font color="#990000">template &lt;class T&gt;
class	CSyncAccess {
.............
	virtual	~CSyncAccess();
	T*	operator -&gt; ();
};
/////////////////////////////////////////////////////////////////////////////</font></tt></pre>

<p>The representation class used in this scenario has a member of type CRITICAL_SECTION.</p>

<pre><tt><font color="#990000">template &lt;class T&gt;
class CSyncAccessRep {
............
	CRITICAL_SECTION	m_CriticalSection;
};
/////////////////////////////////////////////////////////////////////////////</font></tt></pre>

<p>And now let's look at the example code:</p>

<pre><tt><font color="#990000">typedef	SyncPtr&lt;CSomething&gt;	LPSOMETHING;
LPSOMETHING	p = new CSomething;

p-&gt;do();</font></tt></pre>

<p>What's going when <font color="#800000">p-&gt;do()</font> is called? 

<ol>
  <li>The compiler calls <font color="#800000">SyncPtr::operator-&gt;()</font> which returns
    object of type <font color="#800000">CSyncAccess</font>. This object is temporary and is
    stored on top of the stack. In its constructor the critical section object is initialized.
  </li>
  <li>The compiler calls <font color="#800000">CSyncAccess:operator-&gt;()</font> which owns
    the critical section and thus protects other threads to own it and then returns the real
    pointer to the pointed object </li>
  <li>The compiler calls the method <font color="#800000">do()</font> of the pointed object </li>
  <li>The compiler destroys <font color="#800000">CSyncAccess</font> object which is on the
    stack. This calls its destructor where the critical section is released and other threads
    are free to own it.</li>
</ol>

<p>&nbsp;</p>

<p>The good thing about SmartPtr is that pointed objects do not have to be inherited from
any special base class as in many other reference counting implementations. The reference
counter and the real object pointer are stored in dinamically allocated objects of types
CRefCountRep, CSyncAccessRep and CSyncRefCountRep (called representation objects)
depending on what kind of SmartPtr we have. These objects are allocated and freed by
SmartPtr. This approach allows us to have SmartPtr for objects of any classes, not only
for inherited from special base class. Well, this is the weakness of the SmartPtr too.
Imagine that you have a piece of code like this:</p>

<pre><tt><font color="#990000">LPSOMETHING	p1 = new CSomething;
CSomething*	p2 = (CSomething*)p1;
LPSOMETHING	p3 = p2;</font></tt></pre>

<p>As result, at the end of this piece of code you think you will have p1 and p3 point to
the same object. Yes, they will. But they will have diferent representation objects in p1
and p3. So when p3 is destroyed the underlying CSomething object will be destroyed too and
p1 will point to invalid memory. So I have a simple <strong>tip: If you use SmartPtr never
use real pointers to underlying objects</strong> like in the code above. But if you want
you can still use real pointers when dealing with other objects. </p>

<p>Let's look at this code:</p>

<pre><tt><font color="#990000">LPSOMETHING	p1 = new CSomething;
SomeFunc( p1 );

void	SomeFunc( CSomething* pSth ) {
	LPSOMETHING	p3 = pSth;
}</font></tt></pre>

<p>p3 will create its own representation, ie. its own reference counter and when SomeFunc
exits, p3 will free the memory pointed by p1. Instead of this function definition you'd
better define it this way.</p>

<pre><tt><font color="#990000">void	SomeFunc( LPSOMETHING pSth );</font></tt></pre>

<p>I talk about these to notify you that calling SmartPtr <strong><em>constructor</em></strong>
or <em><strong>operator =</strong></em> with T* parameter creates new representation
object and this will lead to &quot;strange&quot; behaviour of SmartPtr.</p>

<p>The mentioned above weakness of the SmartPtr behaviour could be solved if we add static
table of associations - T* &lt;-&gt; CxxxxxRep* and every time SmartPtr gets T* we could
search in this table and get appropriate CxxxRep object if it is already created. But this
will lead to more memory and CPU overhead. And since now I think it is better to follow
mentioned above rule than overheading.</p>

<p>&nbsp;</p>

<p><a name="#efficency"></a><strong><big>SmartPtr is as efficient as regular pointer and
integer values.</big></strong></p>

<p>Here is a table with some sizeof() results:</p>

<table border="1" cellPadding="1" cellSpacing="1" width="100%">
  <tr>
    <th width="35%" bgcolor="#800080">&nbsp;</th>
    <th width="65%" bgcolor="#800080"><font color="#ffffff">Size in bytes</font></th>
  </tr>
  <tr>
    <td width="35%" bgcolor="#e0e0e0">sizeof( SmartPtr )</td>
    <td width="65%" bgcolor="#e0e0e0">4</td>
  </tr>
  <tr>
    <td width="35%" bgcolor="#e0e0e0">sizeof( CSomething* )</td>
    <td width="65%" bgcolor="#e0e0e0">4</td>
  </tr>
  <tr>
    <td width="35%" bgcolor="#e0e0e0">sizeof( int )</td>
    <td width="65%" bgcolor="#e0e0e0">4</td>
  </tr>
</table>

<p>SmartPtr objects have the same size as pointers and int values. So, passing a SmartPtr
objects as function (method) arguments or returning SmartPtr object as function result is
as efficient as doing the same with regular pointer or int value.</p>

<p>&nbsp;</p>

<p><a name="#dif_ptr_types"></a><strong><big>SmartPtr objects can accept different pointer
types.</big></strong></p>

<p>SmartPtr class has a non template base class SmartPtrBase, which is made argument of
various constructors and assignment operators. Thus a code like this is possible to be
used</p>

<pre><tt><font color="#990000">class	B {
.... 
};</font></tt></pre>

<pre><tt><font color="#990000">class	A : public B {
....
};</font></tt></pre>

<pre><tt><font color="#990000">class	C {
....
};</font></tt></pre>

<pre><tt><font color="#990000">RefCountPtr&lt;A&gt;	a = new A;
RefCountPtr&lt;B&gt;	b = a;
b = a;</font></tt></pre>

<p>Even this is very good feature in cases where you need a pointer to base class to hold
objects of inherited classes you may have a code like this</p>

<pre><tt><font color="#990000">RefCountPtr&lt;A&gt;	a = new A;
RefCountPtr&lt;B&gt;	b = new B;
SyncPtr&lt;C&gt;	c = a;
a = b;
a = c;
c = a; 

c = b;</font></tt></pre>

<p>And the compiler will not warn you there are implicit type conversions. Note that there
is no relation between <strong>class C</strong> and <strong>class B</strong>.</p>

<p>In fact, SmartPtr implicitly passes underlying representation objects in such
assignments. The behaviour of the pointer depends on the underlying representation object.
So, no matter what is the intention of the holder pointer (in the example above
&quot;c&quot; is a synchronization pointer) the pointer behaviour depends on the type of
the representation object creator.</p>

<p>In the example above, after the last line (c = b;), &quot;c&quot; will hold the object
pointed by &quot;b&quot;, and even &quot;c&quot; is declared as
&quot;synchronization&quot; pointer when it deals with its object it will behave as
&quot;reference counting&quot; pointer, because the original creator is &quot;b&quot;
which is of such type.</p>

<p>The enclosed demo project is a simple console application and demonstrates different
situations and usage of SmartPtr. It is created by VC ++ 5.0. SmartPtr.h can be compiled
with warning level 4.</p>

<p>That's all.</p>

<p><a href="SmartPtr.zip">Download source</a>&nbsp;&nbsp; SmartPtr.zip (4 KB)<br>
<a href="SmartPtr_demo.zip">Download demo project</a>&nbsp;&nbsp; SmartPtr_demo.zip (12
KB)</p>

<hr>
</body>
</html>

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

Share

About the Author

Stefan Chekanov
Software Developer (Senior) Brosix
Bulgaria Bulgaria
Stefan does programming since his early ages more than 20 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.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150302.1 | Last Updated 13 Jan 2000
Article Copyright 1999 by Stefan Chekanov
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid