歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

C++中智能指針的設計和使用

智能指針(smart pointer)是存儲指向動態分配(堆)對象指針的類,用於生存期控制,能夠確保自動正確的銷毀動態分配的對象,防止內存洩露。它的一種通用實現技術是使用引用計數(reference count)。智能指針類將一個計數器與類指向的對象相關聯,引用計數跟蹤該類有多少個對象共享同一指針。每次創建類的新對象時,初始化指針並將引用計數置為1;當對象作為另一對象的副本而創建時,拷貝構造函數拷貝指針並增加與之相應的引用計數;對一個對象進行賦值時,賦值操作符減少左操作數所指對象的引用計數(如果引用計數為減至0,則刪除對象),並增加右操作數所指對象的引用計數;調用析構函數時,構造函數減少引用計數(如果引用計數減至0,則刪除基礎對象)。

智能指針就是模擬指針動作的類。所有的智能指針都會重載 -> 和 * 操作符。智能指針還有許多其他功能,比較有用的是自動銷毀。這主要是利用棧對象的有限作用域以及臨時對象(有限作用域實現)析構函數釋放內存。當然,智能指針還不止這些,還包括復制時可以修改源對象等。智能指針根據需求不同,設計也不同(寫時復制,賦值即釋放對象擁有權限、引用計數等,控制權轉移等)。auto_ptr 即是一種常見的智能指針。

智能指針通常用類模板實現:

  1. template <class T> 
  2. class smartpointer 
  3. private
  4.     T *_ptr; 
  5. public
  6.     smartpointer(T *p) : _ptr(p)  //構造函數  
  7.     { 
  8.     } 
  9.     T& operator *()        //重載*操作符  
  10.     { 
  11.         return *_ptr; 
  12.     } 
  13.     T* operator ->()       //重載->操作符  
  14.     { 
  15.         return _ptr; 
  16.     } 
  17.     ~smartpointer()        //析構函數  
  18.     { 
  19.         delete _ptr; 
  20.     } 
  21. }; 

實現引用計數有兩種經典策略,在這裡將使用其中一種,這裡所用的方法中,需要定義一個單獨的具體類用以封裝引用計數和相關指針:

  1. // 定義僅由HasPtr類使用的U_Ptr類,用於封裝使用計數和相關指針  
  2. // 這個類的所有成員都是private,我們不希望普通用戶使用U_Ptr類,所以它沒有任何public成員  
  3. // 將HasPtr類設置為友元,使其成員可以訪問U_Ptr的成員  
  4. class U_Ptr 
  5.     friend class HasPtr; 
  6.     int *ip; 
  7.     size_t use; 
  8.     U_Ptr(int *p) : ip(p) , use(1) 
  9.     { 
  10.         cout << "U_ptr constructor called !" << endl; 
  11.     } 
  12.     ~U_Ptr() 
  13.     { 
  14.         delete ip; 
  15.         cout << "U_ptr distructor called !" << endl; 
  16.     } 
  17. }; 

HasPtr類需要一個析構函數來刪除指針。但是,析構函數不能無條件的刪除指針。”

條件就是引用計數。如果該對象被兩個指針所指,那麼刪除其中一個指針,並不會調用該指針的析構函數,因為此時還有另外一個指針指向該對象。看來,智能指針主要是預防不當的析構行為,防止出現懸垂指針。

如上圖所示,HasPtr就是智能指針,U_Ptr為計數器;裡面有個變量use和指針ip,use記錄了*ip對象被多少個HasPtr對象所指。假設現在又兩個HasPtr對象p1、p2指向了U_Ptr,那麼現在我delete  p1,use變量將自減1,  U_Ptr不會析構,那麼U_Ptr指向的對象也不會析構,那麼p2仍然指向了原來的對象,而不會變成一個懸空指針。當delete p2的時候,use變量將自減1,為0。此時,U_Ptr對象進行析構,那麼U_Ptr指向的對象也進行析構,保證不會出現內存洩露。

包含指針的類需要特別注意復制控制,原因是復制指針時只復制指針中的地址,而不會復制指針指向的對象。

Copyright © Linux教程網 All Rights Reserved