c++智能指针实现

来源:互联网 发布:丁香园insight数据库 编辑:程序博客网 时间:2024/06/03 16:49

什么是智能指针,通俗来说,是通过基本类型(模板类)指针,构造类的对象,当此对象销毁时,即调用此对象的析够函数时,释放此指针。也就是用栈中的空间来管理堆中的内存。
STL一共给我们提供了四种智能指针:auto_ptr、unique_ptr、shared_ptr和weak_ptr
auto_ptr和unique_ptr要慎用,原因一样。当auto_ptr的一个对象p1赋值给另一个对象p2时,p1对象的基本类型指针会转移给p2,也就是说,p1对象的指针已指向NULL了。两个所不同的就是,auto_ptr赋值时,编译器允许你这么做,而unique_ptr赋值时,编译器压根不让你这么做,直接报错。
例如
std::auto_ptr p1(new std::string(“auto”) );
std::auto_ptr p2 = p1;
std::string str = *p1;
当再去操作p1内指针时,程序崩溃,因为p1内指针已指向NULL。
而 std::unique_ptr p3(new std::string(“auto”) );
std::unique_ptr p4 = p3;
第二句代码直接编译不通。
无论如何,不太推荐使用它们,因为当你把此两种智能指针放入数组,或者作为参数传递时,(即出现赋值操作时,例如P1 = PS[i]。那么你这个数组里的内容已经废了。)均会对代码造成很大的风险。
而shared_ptr则完全避免了上述问题,因为,此类的内部每进行一次赋值操作时,记录了此指针的引用计数加1。析够此对象时, 引用计数会自动减1。当引用计数为零时,再去释放此指针。唯一缺点,效率上肯定相对于前两种,略低。但是,既然想用对象代替指针,此效率可以忍受,要不然,不推荐使用智能指针。
weak_ptr为辅助shared_ptr出现,属于弱指针类型,而shared_ptr为强指针类型,当shared_ptr的两个对象出现互相引用时,释放后,引用计数永久为1,也就造成了内存泄露。现在就可以利用weak_ptr定义类内部引用shared_ptr对象的对象类型。shared_ptr因为不用多次引用,进而效率也相对较高。
借鉴osg,ref_ptr就是强指针类型,observer_ptr是弱指针类型。
整理osg,强指针类型代码,去除引用对象的观察者,线程控制等代码,整理代码如下(自己所定义的类继承Reference类即可):
template
class ref_ptr
{
public:
typedef T element_type;

    ref_ptr() : _ptr(0) {}    ref_ptr(T* ptr) : _ptr(ptr) { if (_ptr) _ptr->ref(); }    ref_ptr(const ref_ptr& rp) : _ptr(rp._ptr) { if (_ptr) _ptr->ref(); }    template<class Other> ref_ptr(const ref_ptr<Other>& rp) : _ptr(rp._ptr) { if (_ptr) _ptr->ref(); }    ~ref_ptr() { if (_ptr) _ptr->unref();  _ptr = 0; }    ref_ptr& operator = (const ref_ptr& rp)    {        assign(rp);        return *this;    }    template<class Other> ref_ptr& operator = (const ref_ptr<Other>& rp)    {        assign(rp);        return *this;    }    inline ref_ptr& operator = (T* ptr)    {        if (_ptr==ptr) return *this;        T* tmp_ptr = _ptr;        _ptr = ptr;        if (_ptr) _ptr->ref();        // unref second to prevent any deletion of any object which might        // be referenced by the other object. i.e rp is child of the        // original _ptr.        if (tmp_ptr) tmp_ptr->unref();        return *this;    }    // comparison operators for ref_ptr.    bool operator == (const ref_ptr& rp) const { return (_ptr==rp._ptr); }    bool operator == (const T* ptr) const { return (_ptr==ptr); }    friend bool operator == (const T* ptr, const ref_ptr& rp) { return (ptr==rp._ptr); }    bool operator != (const ref_ptr& rp) const { return (_ptr!=rp._ptr); }    bool operator != (const T* ptr) const { return (_ptr!=ptr); }    friend bool operator != (const T* ptr, const ref_ptr& rp) { return (ptr!=rp._ptr); }    bool operator < (const ref_ptr& rp) const { return (_ptr<rp._ptr); }// follows is an implmentation of the "safe bool idiom", details can be found at://   http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool//   http://lists.boost.org/Archives/boost/2003/09/52856.phppublic:    T& operator*() const { return *_ptr; }    T* operator->() const { return _ptr; }    T* get() const { return _ptr; }    bool operator!() const   { return _ptr==0; } // not required    bool valid() const       { return _ptr!=0; }    /** release the pointer from ownership by this ref_ptr<>, decrementing the objects refencedCount() via unref_nodelete() to prevent the Object      * object from being deleted even if the reference count goes to zero.  Use when using a local ref_ptr<> to an Object that you want to return      * from a function/method via a C pointer, whilst preventing the normal ref_ptr<> destructor from cleaning up the object. When using release()      * you are implicitly expecting other code to take over management of the object, otherwise a memory leak will result. */    T* release() { T* tmp=_ptr; if (_ptr) _ptr->unref_nodelete(); _ptr=0; return tmp; }    void swap(ref_ptr& rp) { T* tmp=_ptr; _ptr=rp._ptr; rp._ptr=tmp; }private:    template<class Other> void assign(const ref_ptr<Other>& rp)    {        if (_ptr==rp._ptr) return;        T* tmp_ptr = _ptr;        _ptr = rp._ptr;        if (_ptr) _ptr->ref();        // unref second to prevent any deletion of any object which might        // be referenced by the other object. i.e rp is child of the        // original _ptr.        if (tmp_ptr) tmp_ptr->unref();    }    template<class Other> friend class ref_ptr;    T* _ptr;

};

class Reference
{
public:
Reference(){ _refCount = 0;};

virtual ~Reference(void){};

public:

unsigned long ref(){    return ++_refCount;};unsigned long unref_nodelete(){    return --_refCount;};unsigned long unref(){    int newRef  = --_refCount;    if( newRef == 0 )        delete this;        return newRef;};int referenceCount() const{    return _refCount;}

private:
unsigned long _refCount;
};

原创粉丝点击