#include <iostream>
#include <stdexcept>
using namespace std;
#define TEST_SMARTPTR
class Stub
{
public:
void print() {
// iRef = 1;
cout<<"Stub: print"<< iRef <<endl;
}
Stub() {iRef = 1;};
~Stub(){
cout<<"Stub: Destructor"<<endl;
}
public:
void AddReference(){iRef++;};
int RemoveReference(){ iRef--; return iRef;};
private:
int iRef;
};
class Sentry
{
public:
Sentry(int lock){ lock_ = lock;}
~Sentry(){}
private:
int lock_;
};
template <class T>
class RefCountingTraits
{
public:
void Refer(T* p)
{
Sentry s(lock_);
if( NULL != p )
p->AddReference();
}
void Unrefer(T* p)
{
Sentry s(lock_);
if ( p != NULL )
if(p->RemoveReference() == 0 )
delete p;
}
private:
int lock_;
};
template <class T,class RCTraits = RefCountingTraits<T> >
class SmartPtr :private RCTraits
{
public:
SmartPtr(T *p = 0): ptr(p) { }
SmartPtr(const SmartPtr& src): ptr(src.ptr) {
RCTraits::Refer(ptr);
}
SmartPtr& operator= (const SmartPtr& rhs) {
// self-assigning is also right
//++*rhs.pUse;
RCTraits::Refer(rhs.ptr);
decrUse();
ptr = rhs.ptr;
return *this;
}
T *operator->() {
if (ptr)
return ptr;
throw std::runtime_error("access through NULL pointer");
}
const T *operator->() const {
if (ptr)
return ptr;
throw std::runtime_error("access through NULL pointer");
}
T &operator*() {
if (ptr)
return *ptr;
throw std::runtime_error("dereference of NULL pointer");
}
const T &operator*() const {
if (ptr)
return *ptr;
throw std::runtime_error("dereference of NULL pointer");
}
~SmartPtr() {
decrUse();
#ifdef TEST_SMARTPTR
std::cout<<"SmartPtr: Destructor"<<std::endl;// for testing
#endif
}
private:
void decrUse() {
RCTraits::Unrefer(ptr);
}
T *ptr;
};
int main()
{
try {
SmartPtr<Stub> t;
t->print();
} catch (const exception& err) {
cout<<err.what()<<endl;
}
SmartPtr<Stub> t1(new Stub);
SmartPtr<Stub> t2(t1);
SmartPtr<Stub> t3(new Stub);
t3 = t2;
t1->print();
(*t3).print();
getchar();
return 0;
}