天天看點

智能指針(auto_ptr scoped_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 scoped_ptr)

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>”類中聲明)
           

繼續閱讀