智能指针的发展

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

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

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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值