Smart pointers are very widely used in the C++ world to avoid
any pointers to be left dangling in the memory.
Smart pointers are usually designed with two main goals in mind, namely - to
make ones programming safer and also to make it easier. These are
objects that are similar to normal pointers except that it offers great functionality
while handling the memory. Normally in C++ smart pointers are available as templates,
from which we can directly construct a smart pointer that will reference our class.
Even in complex COM programs, smart pointers are widely used to avoid code that
is error prone to
memory leaks. Overloading the -> operator is useful for creating a smart pointer.
This helps objects act like pointers and in addition perform some action whenever
an object is accessed through them. Similarly the * operator can be overloaded to
return the pointer at any given instance. STL also provides a template
enables smooth handling of memory. Apart from overloading the operators =, * and ->,
it also provides functions to get and release the references. Similarly Microsoft ATL
and COM also provides construction of smart pointers. Here are three major aspects that
are supported by smart pointers that helps improving the quality of client-side COM program
- Construction and Destruction - Construction of a smart
interface pointer can be as simple as initializing the pointer to null or as
complex as calling
CoCreateInstance to retrieve a pointer to the requested interface.
Normally, a smart pointer class's constructor is overloaded to support all of
these various capabilities. The destructor of a smart interface pointer can automatically call
- Copying and Assignment - A smart pointer can overload the assignment operator (=) so that
any attempt to copy the pointer results in an automatic
AddRef call, relieving the programmer
of the burden of reference counting.
- Dereferencing - Last the indirection operator (*) can be overridden by the
smart pointer class to perform some basic error checking, ensuring that the internal "dumb"
pointer is not null or invalid in some other way.
Why write your own Smart Pointer?
Normally it is a painful job in C++ to handle memory. Unlike Java, C++ does
not have the concept of garbage collection wherein it can automatically release the memory once
its reference is
NULL. In C++ it becomes the responsibility of the allocator to deallocate the memory,
otherwise the program consumes the heap. This normally happens when some programmer uses
new to allocate
memory but does not follow-up with
delete once this memory is used. One of the ways to tackle this is to
write a generic template class that will automatically delete the allocated memory. Above all,
everyone would be interested in writing their own smart pointers. This helps in understanding
the concept as well as the internal working of smart pointers in a better way. Since there is a way
where you can commit your own smart pointer, then why not give a try and see how it practically works.
Before implementing a template of a smart pointer, let us consider the example below that will explain
how normally memory leak occurs.
strcpy(str,"This is a test string");
Now if you have a main program that instantiates this class and allocates the memory and
makes a call to the display function. Consider the code below
MyClass* pMyClass=new MyClass();
In the above program you can see that
delete is not called after allocating
new. This certainly leads to memory leaks. Since this is small
piece of program it is easy to track and delete the memory. But in a real world situation
where tracking becomes little difficult, it is always advisable to write a template that
will help you deallocate the memory automatically once the usage is over. Below is a
template class implementation that will help you deallocate the memory
typedef T element_type;
explicit AUTO_PTR(T *pVal = 0) throw()
m_AutoPtr = pVal;
m_AutoPtr = NULL;
AUTO_PTR(const AUTO_PTR<T>& ptrCopy) throw()
m_AutoPtr = ptrCopy;
m_AutoPtr = 0;
AUTO_PTR<T>& operator=(AUTO_PTR<T>& ptrCopy) throw()
m_AutoPtr = &ptrCopy;
m_AutoPtr = 0;
T& operator*() const throw()
T *operator->() const throw()
T *get() const throw()
strcpy(str,"This is a test string");
main() function will have to be modified such that it uses the
class to allocate and deallocate the memory. This is how the
main() function looks after modification
AUTO_PTR<MyClass> b=AUTO_PTR<MyClass>(new MyClass);
How does the above program work?
Look into the
main function. There one pointer of the type
MyClass being created with the help of
At first it enters the
MyClass constructor and allocates the memory
as required. It then enters the
AUTO_PTR constructor and creates a smart pointer of
MyClass. This pointer is used till the life time of the reference
get is called to seek a reference to the class
MyClass and then the function
is called to display the string allocated by the class. Once the reference is used,
it automatically de-references the allocated memory. This happens in reverse order as you
know that the destructors are called in reverse order. Though the program never bothers to
make a call to
delete, Since the working of smart pointers are so that it dereferences the memory,
it first enters the destructor of the
AUTO_PTR to delete the pointer
and then enters the destructor of the class
MyClass to release the memory allocated to the string
variable. Hence at the end of the program the memory is released.
The above example is very simple. This is just to show how small mistakes leads to memory leaks. This can be
elaborated to use the template in a complex scenario. Treat the class
MyClass as an example to show the usage of the template. You can write much more complex classes and use the template to allocate and deallocate the memory.
Have fun experimenting with more complex classes.
Any doubts, contact me at email@example.com