(本站文章均出自原创,转载请注明出处~)
{
public :
explicit RefObject(T * p):m_RefCount( 1 ),m_pContainer(p)
{
}
~ RefObject()
{
decRef();
}
void incRef()
{
++ m_RefCount;
}
void decRef()
{
if ( -- m_RefCount == 0 )
{
destroy();
}
}
T * getPtr()
{
return m_pContainer;
}
private :
void destroy()
{
delete m_pContainer;
m_pContainer = 0 ;
m_RefCount = 0 ;
delete this ;
}
private :
T * m_pContainer;
unsigned int m_RefCount;
private :
RefObject( const RefObject & );
const RefObject & operator = ( const RefObject & );
};
{
public :
SmartPtr():m_pRefObject( 0 )
{
}
explicit SmartPtr(T * p)
{
m_pRefObject = new RefObject < T > (p);
}
SmartPtr( const SmartPtr & other):m_pRefObject(other.m_pRefObject)
{
m_pRefObject -> incRef();
}
~ SmartPtr()
{
if (m_pRefObject)
m_pRefObject -> decRef();
}
const SmartPtr < T >& ff;">operator = ( const SmartPtr & other)
{
if (m_pRefObject != other.m_pRefObject)
{
m_pRefObject = other.m_pRefObject;
m_pRefObject -> incRef();
}
return * this ;
}
T * operator -> () const
{
return m_pRefObject -> getPtr();
}
T & operator * () const
{
return * m_pRefObject -> getPtr();
}
protected :
RefObject < T >* m_pRefObject;
};
SmartPtr类在hold住一个T类指针时就new出一个RefObject与之相对应,重载赋值操作符来实现每赋值一次增加引用计数,析构函数中减少引用计数。并且重载->操作符以使SmartPtr使用起来像一个真正的指针。
{
{
SmartPtr < CSample > spSam( new CSample());
spSame -> DoSomething();
}
}
完全不用delete,实现垃圾自动回收效果,很酷吧。 哈哈,我初次写完这些代码是也觉的很爽,终于体验到了使用Java,C#的感觉了。可是智能指针还有一个致命的问题,这个问题就像是一盘美食中的苍蝇,让你心头非常不爽,并且对智能指针的好感立刻全无。哈哈哈,那就是:循环引用。当你写的类中不幸出现循环引用,那么你的智能指针将
struct A
SmartPtr < B > b;
}
struct B
{
SmartPtr < A > a;
}
int main()
{
SmartPtr < A > aa( new A());
SmartPtr < B > bb( new B());
aa.b = bb;
bb.a = aa;
}
如果你写了以上程序(虽然不常见,因为这种设计是非常糟糕的)你的aa和bb将无法释放!!!导致无法释放的原因是什么?这是因为aa获取了一次bb的所有权,但aa销毁时并没有释放这次获得的所有权,当把bb赋给aa的b时,bb的引用计数变为2,当bb销毁时bb所持有的对象引用减为1,而并不是0,所有他并不会释放他所持有的实际指针。其实
class C
A * a;
C()
{
a = new A();
}
}
类C在构造函数里new了一个A,却并没有在析构函数里delete它!
我的解决方法是设计一个新类:SmartPtrHolder,此类用来存放一个SmartPtr,但并不增加计数。一种比较时髦的解释叫:弱引用。实现大致如下:
public :
SmartPtrHoder():m_pRefObject( 0 )
{
}
SmartPtrHoder( const SmartPtr < T >& sp):m_pRefObject(sp.m_pRefObject)
{
}
SmartPtrHoder & operator = ( const SmartPtr < T >& sp)
{
if (m_pRefObject != sp.m_pRefObject)
{
m_pRefObject = sp.m_pRefObject;
}
return * this ;
}
SmartPtr < T > use()
{
return SmartPtr < T > ( * this );
}
protected :
RefObject < T >* m_pRefObject;
};
这次重载的赋值操作符中并不增加SmartPtr的引用计数。当你需要使用这个SmartPtr时需要调用use()函数来把SmartPtr从SmartPtrHolder中取出来。
另外需要在SmartPtr中增加一个构造函数以支持从SmartPtrHoder中构造出一个SmartPtr。代码如下:
{
m_pRefObject -> incRef();
}
这样再次设计A和B时:
struct A
SmartPtrHolder < B > b;
}
struct B
{
SmartPtrHolder < A > a;
}
这样就不会出现循环引用了。此时我想起了一位大师的话,翻译成中文大致如下:你现在有一个问题,你会说:“嗯~ 我准备用正则表达式来解决这个问题”。现在你有两个问题!