1. 程式人生 > >智能指針原理及實現(1)- shared_ptr

智能指針原理及實現(1)- shared_ptr

red ++ 直接 初始 targe -- div urn 記錄

C++沒有內存回收機制,每次程序員new出來的對象需要手動delete,流程復雜時可能會漏掉delete,導致內存泄漏。於是C++引入智能指針,可用於動態資源管理,資源即對象的管理策略。

一、智能指針類別

智能指針主要有三種:shared_ptrunique_ptrweak_ptr

shared_ptr

shared_ptr是最常用的智能指針(項目中我只用過shared_ptr)。shared_ptr采用了引用計數器,多個shared_ptr中的T *ptr指向同一個內存區域(同一個對象),並共同維護同一個引用計數器。shared_ptr定義如下,記錄同一個實例被引用的次數,當引用次數大於0時可用,等於0時釋放內存:

1 temple<typename T>
2 class SharedPtr {
3 public:
4    ... 
5 private:
6     T *_ptr;
7     int *_refCount;     //should be int*, rather than int
8 };

shared_ptr對象每次離開作用域時會自動調用析構函數,而析構函數並不像其他類的析構函數一樣,而是在釋放內存是先判斷引用計數器是否為0。等於0才做delete操作,否則只對引用計數器左減一操作。

1 ~SharedPtr()
2 {
3     if (_ptr && --*_refCount == 0
) { 4 delete _ptr; 5 delete _refCount; 6 } 7 }

接下來看一下構造函數,默認構造函數的引用計數器為0,ptr指向NULL:

1 SharedPtr() : _ptr((T *)0), _refCount(0)
2 {
3 }

用普通指針初始化智能指針時,引用計數器初始化為1:

1 SharedPtr(T *obj) : _ptr(obj), _refCount(new int(1))
2 {
3 } //這裏無法防止循環引用,若我們用同一個普通指針去初始化兩個shared_ptr,此時兩個ptr均指向同一片內存區域,但是引用計數器均為1,使用時需要註意。

拷貝構造函數需要註意,用一個shared_ptr對象去初始化另一個shared_ptr對象時,引用計數器加一,並指向同一片內存區域:

1 SharedPtr(SharedPtr &other) : _ptr(other._ptr), _refCount(&(++*other._refCount))
2 {
3 }

賦值運算符的重載

當用一個shared_ptr<T> other去給另一個 shared_ptr<T> sp賦值時,發生了兩件事情:

一、sp指針指向發生變化,不再指向之前的內存區域,所以賦值前原來的_refCount要自減

二、sp指針指向other.ptr,所以other的引用計數器_refCount要做++操作。

 1 SharedPtr &operator=(SharedPtr &other)
 2 {
 3     if(this==&other)
 4         return *this;
 5         
 6     ++*other._refCount;
 7     if (--*_refCount == 0) {
 8         delete _ptr;
 9         delete _refCount;
10     }
11         
12     _ptr = other._ptr;
13     _refCount = other._refCount;
14     return *this;
15 }    

定義解引用運算符,直接返回底層指針的引用:

1 T &operator*()
2 {
3     if (_refCount == 0)
4         return (T*)0;
5         
6     return *_ptr;
7 }

定義指針運算符->

1 T *operator->()
2 {
3     if(_refCount == 0)
4         return 0;
5         
6     return _ptr;
7 }

測試:

1 int main(int argc, const char * argv[])
2 {
3     SharedPtr<string> pstr(new string("abc"));
4     SharedPtr<string> pstr2(pstr);
5     SharedPtr<string> pstr3(new string("hao"));
6     pstr3 = pstr2;
7     
8     return 0;
9 }

為了讓測試結果更明顯,我在方法中加入了一些輸出,測試結果如下:

技術分享圖片

源碼鏈接:https://github.com/guhowo/test/tree/master/cplus/SharedPtr

智能指針原理及實現(1)- shared_ptr