智能指针(auto_ptr scoped_ptr)

auto_ptr
    用法一:  
    std::auto_ptr<ClassName>m_example(new ClassName ());  
      
    用法二:  
    std::auto_ptr<ClassName >m_example;  
    m_example.reset(new  ClassName());  
      
    用法三(指针的赋值操作):  
    std::auto_ptr<ClassName>m_example1(new ClassName());  
    std::auto_ptr<ClassName>m_example2(new ClassName());  
    m_example2=m_example1; 
    auto_ptr会自动释放内存,则C++会把m_example所指向的内存回收,使m_example1 的值为NULL,所以在C++中,应绝对避免把auto_ptr放到容器中:vector<auto_ptr<MyClass>>m_example;
    当用算法对容器操作的时候,很难避免STL内部对容器中的元素实现赋值传递,这样便会使容器中多个元素被置位NULL。正确运用auto_ptr让你的代码更加安全,而对auto_ptr危险但常见的误用会引发间断性发作、难以诊断的bug,而auto_ptr只是众多可能的智能指针之一。许多商业库提供了更复杂的智能指针,用途广泛而令人惊异,从管理引用的数量到提供先进的代理服务。可以把标准C++ auto_ptr看作是一个简易、通用的智能指针,它不包含所有的小技巧,不像专用的或高性能的智能指针。 
    模拟实现auto_ptr中赋值运算符重载:      
     
    #include<iostream>
    using namespace std;
     template <class T>
    class AutoPtr
    {
    public:
         AutoPtr(T* ptr = NULL)
              : _ptr(ptr)
         {
              cout << "AutoPtr()" << endl;
         }
         AutoPtr(AutoPtr &ap)
              :_ptr(ap._ptr)//移交管理权
         {
              if (_ptr)
              {
                  ap._ptr = NULL;
              }
         }
         AutoPtr<T>& operator =(AutoPtr &ap)
         {
              if (this != &ap)
              {
                  delete _ptr;
                  _ptr = ap._ptr;
                  ap._ptr = NULL;
                  return *this;
              }
         }
         ~AutoPtr()
         {
              if (_ptr)
              {
                  cout << "~AutoPtr()" << endl;
                  delete _ptr;
                  _ptr = NULL;
              }
         }
         T& operator*()
         {
              return *_ptr;
         }
         T* operator->()
         {
              return _ptr;
         }
    protected:
         T* _ptr;
    };
    void TestAutoPtr()
    {
         AutoPtr<int> ap1(new int);
         *ap1 = 10;
         AutoPtr<int> ap2 = ap1 ;
         AutoPtr<int> ap3(new int(20));
         ap2 = ap3;
    }
    int main()
    {
         TestAutoPtr();
         system("pause");
         return 0;
    }

    打开内存窗口就会发现将ap1赋值给ap2之后ap1的空间也会释放

    auto_ptr特点:

    1. 利用特点“栈上对象在离开作用范围时会自动析构”。

    2. 对于动态分配的内存,其作用范围是程序员手动控制的,这给程序员带来了方便但也不可避免疏忽造成的内存泄漏,毕竟只有编译器是最可靠的。
    3. auto_ptr通过在栈上构建一个对象a,对象a中 包含了动态分配内存的指针p,所有对指针p的操作都转为对对象a的操作。而在a的析构函数中会自动释放p的空间,而该析构函数是编译器自动调用的。
    实例如下:
     
    #include <iostream> 
    #include <memory> 
    using namespace std; 
    class A 
    { 
    public: 
         A()
         {
              cout<<"A()"<<endl;
         } 
         ~A()
         {
              cout<<"~A()"<<endl;
         } 
    }; 
    void fun(bool isThrow) 
    {  
         //A *pa= new A;            // 方法1
         //try 
         //{ 
         //   if(isThrow) 
         //        throw " throw a date "; 
         //} 
         //catch(const char* e) 
         //{ 
         //   
         //   throw; 
         //} 
         auto_ptr<A> A(new A);    // 方法2
     
         try 
         { 
              if(isThrow) 
                  throw "throw a date"; 
         } 
         catch(const char* e) 
         {   
              throw; 
         } 
         
         
    } 
    int main() 
    { 
         try 
         { 
              fun(true); 
         } 
         catch(...) 
         { 
              cout<<"caught"<<endl; 
         } 
         system("pause"); 
    }

     如果采用方案1,那么必须考虑到函数在因throw异常的时候释放所分配的内存,这样造成的结果是在每个分支处都要很小心的手动 delete A;。
      如果采用方案2,那就无需操心何时释放内存,不管fun()因何原因退出, 栈上对象A的析构函数都将调用,因此托管在之中的指针所指的内存必然安全释放。
    至此,智能指针的优点已经很明了了。
    但是要注意使用中的一个陷阱,那就是指针的托管权是会转移的。使用赋值运算符重载操作后源变量指针就会变空,因此再用源指针调用就会出现问题。要避免这个问题,可以考虑使用采用了引用计数的智能指针,例如boost::shared_ptr等。auto_ptr不会降低程序的效率,但auto_ptr不适用于数组,auto_ptr根本不可以大规模使用。 shared_ptr也要配合weaked_ptr,否则会很容易触发循环引用而永远无法回收内存。
    scopedptr

    因为智能指针容易出现拷贝时释放两次的情况,所以ScopedPtr主要是进行防止拷贝,防止拷贝的两条必须要满足的条件是:

             (1)设置保护限定符,
             (2)对拷贝构造函数和赋值运算符重载进行之声明不定义。
       如若只有(2),没有设置保护限定符,若在类外进行定义后,则会出现问题,所以说这两个条件是必不可少的。这样就能够避免上面所出现的问题,但是这样就造成了它在功能上的缺陷。
     
    //ScopedPtr    实现简单的智能指针进行防拷贝
    template <class T>
    class ScopedPtr
    {
    public:
         ScopedPtr(T * ptr)
              :_ptr(ptr)
         { }
         ~ScopedPtr()
         {
              cout << "delete" << endl;
              if (_ptr)
              {
                  delete _ptr;
                  _ptr = NULL;
              }
         }
         T & operator*()
         {
              return *_ptr;
         }
         T* operator->()
         {
              return _ptr;
         }
         T* GetPtr()
         {
              return _ptr;
         }
    protected:     //防止拷贝
         ScopedPtr(ScopedPtr<T> & ap);
         ScopedPtr<T> & operator=(ScopedPtr<T> & ap);
    private:
         T * _ptr;
    };
     当调用拷贝构造和赋值运算符重载时就会出现下面错误
    1>f:\程序\智能指针\智能指针\scopedptr.cpp(46) : error C2248: “ScopedPtr<T>::ScopedPtr”: 无法访问protected 成员(在“ScopedPtr<T>”类中声明)


    • 1
      点赞
    • 0
      收藏
      觉得还不错? 一键收藏
    • 0
      评论

    “相关推荐”对你有帮助么?

    • 非常没帮助
    • 没帮助
    • 一般
    • 有帮助
    • 非常有帮助
    提交
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值