custom smart pointer class template
The Big Issue

One of the biggest things about smart pointers is that they guarantee deletion of the pointer. EVEN when exceptions happen. My main problem here is that your constructor may leak the pointer if it fails to initialize correctly.

template &lt;class T&gt;
SmartPtr&lt;T&gt;::SmartPtr(T* iObject):
    _refCount(new RefCount()),       // This can throw.
    _ptr(iObject)
{   
    this-&gt;_refCount-&gt;AddRef();
}


If the creation of the _refCount object fails you will leak the pointer. You need to guarantee that the pointer does not leak:

SmartPtr&lt;T&gt;::SmartPtr(T* iObject)
try                               // Add a try block
    :_refCount(new RefCount())
    ,_ptr(iObject)
{   
    this-&gt;_refCount-&gt;AddRef();
}
catch(...)
{
    delete iObject;    // If there is an exception make sure the object is deleted.
    throw;             // Then re-throw the exception.
}


Minor Missing Functions

The main missing things I see are:

 T*  get();            // Sometimes its nice to just get the pointer.
 operator bool();      // Nice when you want to simply check the smart
                       // pointer has something in a boolean context.

 SmartPtr&lt;Stuff&gt;  data = getSmartPointer();
 if (data) {
     data-&gt;doWork();   // Need to check there is a pointer in the
 }                     // object before calling doWork().


Constructor Problems

Explicit

Your one parameter constructor should be explicit. Think of this situation.

 void doStuff(SmartPtr&lt;Stuff&gt; work)
 {
      if (work) {
          work-&gt;doWork();
      }
 }


Looks simple enough. When you call the function you get another reference counted version of the pointer and thus it is simple and safe to use.

But what happens when I do this:

int main()
{
    Stuff*  work = new Stuff;
    doStuff(work);
    work-&gt;moreActions();
    delete work;
}


This code compiles. But the call to doStuff() results in delete being called on the work object. Even though you though it was safe to call (as you are making a copy of smart pointer).

The trouble is that the compiler has converted the Stuff* to a SmartPtr which is deleted in this scope.

What About nullptr

Your object does not accept a nullptr!

 SmartPtr&lt;Stuff&gt;  value = nullptr;  // fails to compile.


It does not look like a major problem. But when you start using templatized code where things are initialized and your type can be swapped in then it becomes an issue as your type can not be used.

What About Derived Types.

On of the major things about C++ is derived types with more functionality.

Derived*    x = new Derived;
Base*       y = x;


The same should work with smart pointers.

SmartPtr&lt;Derived&gt;  x = new Derived;
SmartPtr&lt;Base&gt;     y = x;           // fails to compile.


This will be a common in most C++ code (not exactly like this). But this functionality is really needed.

Make Shared

One of the things the standard builders found was that each shared pointer required the allocation of TWO objects. One for the thing and one for the counter.

They remedied this by introducing std::make_shared&lt;T&gt;(). This does one allocation that allocates the object and the counter inside the same space thus reducing the overall overhead of the object.

Further Reading

I cover a lot of these details and more in some articles I wrote:

Series
Smart-Pointer - Unique Pointer
Smart-Pointer - Shared Pointer
Smart-Pointer - Constructors