introduction
smart pointers are classes that store pointers to dynamically allocated
(heap) objects. they behave much like built-in c++ pointers except that
they automatically delete the object pointed to at the appropriate
time. smart pointers are particularly useful in the face of exceptions
as they ensure proper destruction of dynamically allocated objects.
they can also be used to keep track of dynamically allocated objects
shared by multiple owners.
one of the most important techniques of implementing smart pointers is using reference count method.most of you have rolled your own smart pointers, and there is plenty of
literature regarding the issues involved in reference counting. one of
the most important details is how the reference count is implemented —
intrusive, which means that you add support to the classes being
reference counted, or non-intrusive, which means you don’t. my implementation
is non-intrusive, and the implementation uses a simple integer reference counter.
background
you must know the basic concepts of parameter passing of c++ to understand the reference counting mechanism. in c++,we have two types of parameter passing:
1)pass by value.
2)pass by reference.
in pass by value,a temporary copy of the data type being passed is created.in pass be reference, the address of the parameter being passed is sent so that any changes to the passed parameter is directly reflected to the state of the passed parameter.
now,if we pass and user-defined object as a parameter to a function,the copy-constructor of the function is called to create a temporary object,which is destroyed as soon as the function returns. i have used this concept to create the shared pointer implementation for automatic garbage collection.
using the code
this is a very simple implementation of the shared pointer concept. i have used a templated class which wraps a pointer to a reference counting object. this object wraps the pointer to the class passed as the template argument.
the implementation is very simple. it has a de-referencing operator which returns the wrapped pointer object when used. whenver, the shared pointer is passed as a argument to function or any situation in which a copy constructor is involved,its reference count is incremented. this reference count is decremented in the destructor which when it reaches 0,the wrapped pointer is freed.
:
template <class t> class refcounter_impl {
private:
int m_counter;
t* m_obj;
public:
void inc_ref_count()
{
++m_counter;
}
void dec_ref_count()
{
--m_counter;
if(m_counter<=0)
{
destroy_ref();
}
}
t * get_ptr() const
{
return ((t *)this);
}
void destroy_ref()
{
if(get_ptr()!=null)
delete get_ptr();
}
const t& operator=(const refcounter_impl<t>& ref)
{
this->m_obj = ref.m_obj;
m_counter = ref.m_counter;
inc_ref_count();
}
refcounter_impl(t* obj):m_counter(0),m_obj(obj){}
refcounter_impl(const refcounter_impl<t>& ref)
{
this->m_obj = ref.m_obj;
m_counter = ref.m_counter;
inc_ref_count();
}
};
<class t>
class shared_ptr
{
private:
refcounter_impl<t>* m_refcounted_obj;
void assign(void *ptr)
{
if(ptr==null)
assign((refcounter_impl<t> *)null);
else
{
assign(new refcounter_impl<t>(static_cast<t *>(ptr)));
}
}
void assign(refcounter_impl<t> *refcount)
{
if(refcount!=null)
refcount->inc_ref_count();
m_refcounted_obj = refcount;
}
public:
shared_ptr() :m_refcounted_obj(null){}
shared_ptr(t* obj) :m_refcounted_obj(null)
{
assign(obj);
}
shared_ptr(const shared_ptr& ref)
{
assign(ref.m_refcounted_obj);
}
shared_ptr& operator=(const shared_ptr& ref)
{
assign(ref.m_refcounted_obj);
return *this;
}
t* operator->()
{
if(m_refcounted_obj)
return m_refcounted_obj->get_ptr();
else
return null;
}
~shared_ptr()
{
m_refcounted_obj->dec_ref_count();
}
};
conclusion
- this is a very simple implementation of the shared pointer technique,and i have kept this deliberately for intermediate users. advanced users might not refer this article but this would extremely useful for people with 2-3 years of development experience moving on to implementing bigger things.
points of interest
- i particularly enjoyed to explore the c++ argument passing mechanism while writing this article.
- you can download the concepts.zip folder to see the complete c++ code with an example of my implementation.