// if (!sPtr2.isAssigned ()) // SmartPtr::isAssigned() returns false if no reference is being held
// cout << "sPtr2 is not holding any reference" << endl;
// sPtr2 = new T; // make a new oject of T and pass ownership to sPtr
//
#include <algorithm>
//#define NULL nullptr
template<class T>
class SmartPtr
{
public:
// create a new object which is not
// refering to any object on heap.
// no-throw guarantee
explicit SmartPtr ()
: m_pT (NULL),
m_pRefCount (NULL)
{
}
// new object will point to a memory location on heap given by 'pObj'
// Strong exception guarantee
explicit SmartPtr (T *pObj)
: m_pT (pObj),
m_pRefCount (NULL)
{
try
{
m_pRefCount = new int;
}
catch (...)
{
checkedDelete (m_pT);
throw;
}
*m_pRefCount = 1;
}
// new object will refer to same memory on heap as 'rObj'
// no-throw guarantee
SmartPtr (const SmartPtr<T> &rObj)
: m_pT(rObj.m_pT),
m_pRefCount(rObj.m_pRefCount)
{
if (m_pRefCount != NULL)
(*m_pRefCount)++;
}
// make 'rObj' and 'this' will refer to same object on heap
// no-throw guarantee
SmartPtr& operator= (const SmartPtr<T> &rObj)
{
// uses copy-and-swap idiom
this_type(rObj).swap(*this);
return *this;
}
// assign this smart pointer to another object on heap
// Strong exception guarantee
SmartPtr& operator= (T *pTObj)
{
// try and setup memory for reference counter
int *pNewRefCount;
try
{
pNewRefCount = new int;
}
catch (...)
{
delete pTObj;
throw;
}
// stop referring to previous object
updateCountAndTriggerDelete ();
// start referring to new object
m_pRefCount = pNewRefCount;
*m_pRefCount = 1;
m_pT = pTObj;
return *this;
}
// no-throw guarantee
~SmartPtr ()
{
updateCountAndTriggerDelete ();
}
// returns true if this object is holding a reference
// to an object on heap
// no-throw guarantee
bool isAssigned()
{
return !(m_pT == NULL);
}
// no-throw guarantee
T* operator->()
{
return m_pT;
}
// no-throw guarantee
T& operator*()
{
return *m_pT;
}
private:
// make sure we dont delete a incomplete type pointer
// no-throw guarantee
template <class S>
void checkedDelete (S* pSObj)
{
typedef char type_must_be_complete[ sizeof(S)? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete pSObj;
}
// count the references and delete it if this is last reference
// no-throw guarantee
void updateCountAndTriggerDelete ()
{
if (m_pRefCount != NULL)
{
(*m_pRefCount)--;
// if this is last reference delete the memory
if (*m_pRefCount == 0)
{
checkedDelete (m_pRefCount);
checkedDelete (m_pT);
}
}
}
// swap the pointer values of 'rObj' with values of 'this'
// no-throw guarantee
void swap (SmartPtr<T> &rObj)
{
std::swap (m_pT, rObj.m_pT);
std::swap (m_pRefCount, rObj.m_pRefCount);
}
// pointer to memory location of object
T *m_pT;
// pointer to memory location where 'reference' count of
// object pointed to by m_pT is kept
int *m_pRefCount;
typedef SmartPtr<T> this_type;
};
int main()
{
int *oldPtr = new int();
SmartPtr<int> sPtr= oldPtr;
SmartPtr<int> sPtr2;
sPtr2= oldPtr;
}