智能指针的发展

来源:互联网 发布:点歌软件电脑 编辑:程序博客网 时间:2024/06/05 17:11

通常是经由类模板来实现。借由模板来达成泛型,通常借由类的析构函数来达成自动释放指针所指向的内存或对象。

智能指针的最初动机是使得下面的代码更安全,最初使用

void foo(){    Type* ptr = new Type[10];    // 对p指向的内存块进行赋值    do_something();    delete[] ptr;}

当上面的foo()函数出现异常时:

void foo(){    MyClass* p;    try {        p = new MyClass;        p->DoSomething();        delete p;    }    catch (...) {        delete p;        throw;    }}

当程序代码越来越长时,程序代码会显得臃肿不堪

auto_ptr:
在使用auto_ptr时,须十分注意资源所有权的概念。auto_ptr是现在标准库里面一个轻量级的智能指针的实现,存在于头文件 memory中,之所以说它是轻量级,是因为它只有一个成员变量(拥有对象的指针),相关的调用开销也非常小。
当有了智能指针时我们可以将上面的代码进行如下改写:

void foo(){    auto_ptr<MyClass> p(new MyClass);    p->DoSomething();}

下面我们来看看auto_ptr实现了些什么:(以下的auto_ptr的声明摘自ISO/IEC 14882, section 20.4.5:)

namespace std {    template <class Y> struct auto_ptr_ref {};    template <class X>    class auto_ptr {    public:        typedef X element_type;        // 20.4.5.1 construct/copy/destroy:        explicit           auto_ptr(X* p =0) throw();                           auto_ptr(auto_ptr&) throw();        template <class Y> auto_ptr(auto_ptr<Y>&) throw();        auto_ptr&                      operator=(auto_ptr&) throw();        template <class Y> auto_ptr&   operator=(auto_ptr<Y>&) throw();        auto_ptr&                      operator=(auto_ptr_ref<X>) throw();        ~auto_ptr() throw();        // 20.4.5.2 members:        X&     operator*() const throw();        X*     operator->() const throw();        X*     get() const throw();        X*     release() throw();        void   reset(X* p =0) throw();        // 20.4.5.3 conversions:                                    auto_ptr(auto_ptr_ref<X>) throw();        template <class Y> operator auto_ptr_ref<Y>() throw();        template <class Y> operator auto_ptr<Y>() throw();    };}

再来看看赋值运算符的重载和拷贝构造的写法:

//拷贝构造auto_ptr(_Myt& _Right) _THROW0()        : _Myptr(_Right.release())        {}auto_ptr(auto_ptr_ref<_Ty> _Right) _THROW0()        {            _Ty *_Ptr = _Right._Ref;            _Right._Ref = 0;    // release old            _Myptr = _Ptr;  // reset this        }//赋值_Myt& operator=(_Myt& _Right) _THROW0(){   // assign compatible _Right (assume pointer)    reset(_Right.release());    return (*this);}_Myt& operator=(auto_ptr_ref<_Ty> _Right) _THROW0(){   // assign compatible _Right._Ref (assume pointer)    _Ty *_Ptr = _Right._Ref;    _Right._Ref = 0;    // release old    reset(_Ptr);    // set new    return (*this);}//release_Ty *release() _THROW0(){       _Ty *_Tmp = _Myptr;    _Myptr = 0;    return (_Tmp);}

eg1:

   MyClass* p(new MyClass);   MyClass* q = p;  delete p;  p->DoSomething();       p = NULL;               q->DoSomething();    

可以看出:auto_ptr只是简单的把新构造的对象q 指向了p 的内存空间。delete p 之后 p 可能依然指向某块内存(悬挂的)但是却是无效的指针。

eg2:

void main(){    auto_ptr<MyClass> p(new MyClass);    auto_ptr<MyClass> q(p);}

eg3:

void main(){    auto_ptr<MyClass> p(new MyClass);    auto_ptr<MyClass> q(new MyClass);   {       q = p;    }    //恢复对p的操作,就找不到p}

q指向了p的内存,出作用域后先析构q,p指向空然而这时的p已经找不到了,导致p依然指向某块内存,但却是无效的指针。

简洁版auto_ptr:

template <class T>class SmartPtr{public :`     SmartPtr(T * ptr = NULL)         : _ptr(ptr )    {}    ~ SmartPtr()    {          if (_ptr )         {              delete _ptr ;         }    }     SmartPtr(SmartPtr & ap)         : _ptr(ap ._ptr)    {          ap._ptr = 0;    }     SmartPtr& operator =(SmartPtr& ap)    {          if (this != &ap)         {              _ptr = ap ._ptr;              ap._ptr = 0;         }          return *this ;    }     T* GetPtr()    {          return _ptr;    }     T& operator * ()    {          return *_ptr ;    }     T* operator -> ()    {          return _ptr ;    }private :     T* _ptr ;};void Test1 (){     SmartPtr<int > p1 = new int (10);     SmartPtr<int > p2 = p1;     SmartPtr<int > p3;     p3 = p2 ;     // *p1 = 4;}

auto_ptr的几点注意事项:
1、auto_ptr不能共享所有权
2、auto_ptr不能指向数组
3、auto_ptr不能作为容器的成员
4、不能通过复制操作来初始化auto_ptr
std::auto_ptr p(new int(42)); //OK
std::atuo_ptrp = new int(42);//Error
这是因为auto_ptr的构造函数被定义了explicit
5、不要把auto_ptr放入容器

对象复制给另一个 auto_ptr p2对象以后,p1则被置空,如果访问p1,则会出现非法访问, auto_ptr 的接口设计存在缺陷!

uniqu-ptr(socped_ptr):
uniqu_ptr的拷贝构造函数和赋值运算符都声明为deleted,也就是说它不能被拷贝,只能通过std::move来转递它所指向的内存的所有权。

std::unique_ptr<int> p1(new int(5));std::unique_ptr<int> p2 = p1; // 编译会出错std::unique_ptr<int> p3 = std::move (p1); // 转移所有权,现在那块内存归p3所有, p1成为无效的指针。p3.reset(); //释放内存。p1.reset(); //实际上什么都没做。std::auto_ptr依然存在,但在C++11中被标为"弃用".

简洁版unique_ptr:

template <class T>class SmartPtr{public :     SmartPtr(T * ptr = NULL)         : _ptr(ptr )    {}    ~ SmartPtr()    {          if (_ptr )         {              delete _ptr ;         }    }     T* GetPtr()    {          return _ptr ;    }     T& operator * ()    {          return *_ptr ;    }     T* operator -> ()    {          return _ptr ;    }private :     SmartPtr(SmartPtr & ap);     SmartPtr& operator =(SmartPtr& ap);    //!=     //==   拷贝构造 和赋值 不被允许  则这两个也没有意义private :     T* _ptr ;};void Test1 (){     SmartPtr<int > p1 = new int (10);     //SmartPtr<int> p2 = p1;     //SmartPtr<int> p3;     //p3 = p2;}

shared_ptr
shared_ptr对象除了包括一个所拥有对象的指针(px)外,还必须包括一个引用计数代理对象(shared_count)的指针(pn)。而这个引用计数代理对象包括一个真正的多态的引用计数对象(sp_counted_base)的指针(_pi),真正的引用计数对象在使用VC编译器的情况下包括一个虚表,一个虚表指针,和两个计数器
shared_ptr完美解决auto_ptr在对象所有权上的局限性(auto_ptr是独占的),在使用引用计数的机制上提供了可以共享所有权的智能指针。

template <class T>class SmartPtr{public :    SmartPtr(T* ptr = NULL)         : _ptr(ptr )         , _countPtr(new int(1))    {}         ~ SmartPtr()    {          Release();    }     SmartPtr(const SmartPtr& ap)         : _ptr(ap ._ptr)         , _countPtr(ap ._countPtr)    {         ++ _countPtr[0];    }     SmartPtr& operator =(const SmartPtr& ap )    {          if (this != &ap)         {              this->Release ();              _ptr = ap ._ptr;              _countPtr = ap ._countPtr;             ++ _countPtr[0];         }          return *this ;    }     T* GetPtr ()    {          return _ptr ;    }     int GetCount ()    {          return *_countPtr ;    }     T& operator * ()    {          return *_ptr ;    }     T* operator -> ()    {          return _ptr ;    }protected :     void Release ()    {          if (--_countPtr [0] == 0)         {              delete _countPtr ;              if (_ptr )             {                  delete _ptr ;             }         }    }private :     T* _ptr ;     int* _countPtr ;};void Test1 (){     SmartPtr<int > p1 = new int (1);     cout<<"p1->count:" <<p1. GetCount()<<endl ;     SmartPtr<int > p2 = p1;     cout<<"p1->count:" <<p1. GetCount()<<" " ;     cout<<"p2->count:" <<p2. GetCount()<<endl ;     SmartPtr<int > p3;     p3 = p2 ;     cout<<"p1->count:" <<p1. GetCount()<<" " ;     cout<<"p2->count:" <<p2. GetCount()<<" " ;     cout<<"p3->count:" <<p3. GetCount()<<endl ;}

还有shared_array

template <class T>class SmartArrayPtr{public :     SmartArrayPtr(T * ptr = NULL)         : _ptr(ptr )         , _countPtr(new int(1))    {}    ~ SmartArrayPtr()    {          Release();    }     SmartArrayPtr(const SmartArrayPtr& ap)         : _ptr(ap ._ptr)         , _countPtr(ap ._countPtr)    {         ++ _countPtr[0];    }     SmartArrayPtr& operator =(const SmartArrayPtr& ap)    {          if (this != &ap)         {              this->Release ();              _ptr = ap ._ptr;              _countPtr = ap ._countPtr;             ++ _countPtr[0];         }          return *this ;    }     T* GetPtr ()    {          return _ptr ;    }     int GetCount ()    {          return *_countPtr ;    }    T& operator [](size_t index)    {          return _ptr [index];    }protected :     void Release ()    {          if (--_countPtr [0] == 0)         {              delete _countPtr ;              if (_ptr )             {                  delete[] _ptr ;             }         }    }private :     T* _ptr ;     int* _countPtr ;};void Test2 (){     SmartArrayPtr<int > p1 = new int [20];     cout<<"p1->count:" <<p1. GetCount()<<endl ;     SmartArrayPtr<int > p2 = p1;     cout<<"p1->count:" <<p1. GetCount()<<" " ;     cout<<"p2->count:" <<p2. GetCount()<<endl ;     SmartArrayPtr<int > p3;     p3 = p2 ;     cout<<"p1->count:" <<p1. GetCount()<<" " ;     cout<<"p2->count:" <<p2. GetCount()<<" " ;     cout<<"p3->count:" <<p3. GetCount()<<endl ;     p1[1] = 1;     p3[2] = 2;     cout<<p1 [1]<<" "<< p1[2]<<endl ;}
1 0
原创粉丝点击