实战智能指针(Smart Pointer)
(本站文章均出自原创,转载请注明出处~)
{
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;
}
这样就不会出现循环引用了。此时我想起了一位大师的话,翻译成中文大致如下:你现在有一个问题,你会说:“嗯~ 我准备用正则表达式来解决这个问题”。现在你有两个问题!