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

智能指針的實現

看到了迭代器這裡,想到了應該把智能指針的知識總結一下了,我實現了三種智能指針,分別是auto_ptr,scoped_ptr,shared_ptr命名是根據boost庫中的智能指針命名的

什麼是智能指針?智能指針可以幫助你在忘記釋放new出來的內存的時候自動幫助你釋放內存 可以有效避免內存洩漏 例如當異常出現,跳轉之後。。。內存是應該被釋放的呀,一直抓住人家不放會造成內存洩漏哦 智能指針就是RAII(資源分配即初始化)一種典型的應用   利用類的構造函數和析構函數來進行內存的開辟和釋放,智能指針不能完全說成是指針,它是一種類型用來管理指針的釋放,當出了作用域之後,就回去進行內存釋放 為了要讓智能指針更像一個指針,需要對運算符進行重載:例如*引用       以上就是auto_ptr的部分代碼,但是有個很明顯的問題,那就是沒有拷貝構造函數 當沒有書寫拷貝構造函數使用默認的拷貝構造函數的時候,這種語句就很危險了,涉及到深淺拷貝的問題,如何解決這種問題呢? 下面就講!~ auto_ptr ——》自動釋放指針(大坑貨):拷貝賦值之後,將前一個對象置空,這就完成了只釋放一次(當出現拷貝的情況,兩個指針分別釋放其所指向的同一個空間就會boom!) scoped_ptr——》守衛——》防拷貝:簡單粗暴利用pravate不給你訪問權限,不允許拷貝(既然拷貝會出錯,那不拷貝不就沒事了?) shared_ptr——》共享——》引用計數:采用指針引用計數的方式進行,不采用普通類型,也不用靜態變量,就是要用指針(其實最推薦使用的居然是仿拷貝指針,就是說,沒必要拷貝就別拷貝了,必須拷貝再用共享指針) 貼出代碼!
 1 class AutoPtr
 2 {
 3 public:
 4     explicit AutoPtr(T* ptr=NULL)
 5         :_ptr(ptr)
 6     {
 7     }
 8     AutoPtr(AutoPtr& ap)
 9         :_ptr(ap._ptr)
10     {
11         ap._ptr = NULL;
12     }
13     ~AutoPtr()
14     {
15         delete _ptr;
16     }
17     AutoPtr& operator=(AutoPtr& ap)
18     {
19         if (_ptr != ap._ptr)
20         {
21             if (NULL == _ptr)
22             {
23                 _ptr = ap._ptr;
24                 ap._ptr = NULL;
25             }
26             else
27             {
28                 delete _ptr;
29                 _ptr = ap._ptr;
30                 ap._ptr = NULL;
31             }
32         }
33         return *this;
34     }
35     T& operator *()
36     {
37         return *_ptr;
38     }
39     T* operator->()
40     {
41         return _ptr;
42     }
43     T* GetPtr()
44     {
45         return _ptr;      
46     }
47 private:
48     T* _ptr;
49 };
50 
51 
52 
53 void test1()
54 {
55     AutoPtr<int > ap1 = new int;//支持強轉(這裡的意思是,new產生的int *會被強轉成auto_ptr指針,就是說會拿int *構造臨時的auto_ptr變量然後再賦值)
56     AutoPtr<int > ap2 = new int;
57     //AutoPtr<int >ap3(ap1);//當心,深淺拷貝
58     AutoPtr<int > ap4;
59     ap4 = ap1;
60     ap2 = ap1;
61     /*int *p1 = new int;
62     int *p2 = new int;
63     delete p1;
64     delete p2;*/
65 }

PS:最長注釋的那句AutoPtr<int > ap1 = new int;如果不希望這種事情發生的話要用到explicit關鍵字

我把測試用例也貼出來了~auto_ptr的實現還是非常簡單的,但是就是太坑了,最好不要使用~

接下來是防拷貝智能指針scoped_ptr

 1 #include<iostream>
 2 using namespace std;
 3 
 4 
 5 
 6 template<class T>
 7 class ScopedPtr
 8 {
 9 public:
10     explicit ScopedPtr(T* ptr=NULL)
11         :_ptr(ptr)
12     {
13     }
14     ~ScopedPtr()
15     {
16         if (_ptr)
17         {
18             delete _ptr;
19         }
20     }
21     T* operator ->()
22     {
23         return _ptr;
24     }
25     T& operator *()
26     {
27         return *_ptr;
28     }
29     T* GetPtr()
30     {
31         return _ptr;
32     }
33 
34 private:
35     ScopedPtr(ScopedPtr& sp)
36     {
37 
38     }
39     ScopedPtr& operator=()
40     {
41 
42     }
43 private:
44     T* _ptr;
45 };
46 
47 
48 
49 void test1()
50 {
51 
52     ScopedPtr<int> sp1 = new int(1);
53     ScopedPtr<int> sp2 = new int(2);
54     ScopedPtr<int> sp3(sp1);
55 }

執行這個代碼的話就會報編譯錯誤啦,因為拷貝構造放在私有成員裡了,是不能使用哒,實現也非常簡單,就把關於拷貝的東西全都丟給private就對了

 接下來是共享指針shared_ptr
 1 #include<iostream>
 2 using namespace std;
 3 template<class T>
 4 class SharedPtr
 5 {
 6 public:
 7     explicit SharedPtr(T* ptr)
 8         :_ptr(ptr)
 9         ,_pCount(new int(1))
10     {
11 
12     }
13     SharedPtr(SharedPtr& sp)
14         :_ptr(sp._ptr)
15         ,_pCount(sp._pCount)
16     {
17         (*_pCount)++;
18     }
19     ~SharedPtr()
20     {
21         if (--(*_pCount) == 0)
22         {
23             delete _ptr;
24             delete _pCount;
25         }
26     }
27     SharedPtr& operator=(SharedPtr& sp)
28     {
29         if (_ptr != sp._ptr)
30         {
31             if (NULL == _ptr)
32             {
33                 _ptr = sp._ptr;
34                 _pCount = sp._pCount;
35             }
36             else
37             {
38                 _Release();
39             }
40         }
41         return *this;
42     }
43     T& operator*()
44     {
45         return *_ptr;
46     }
47     T* operator->()
48     {
49         return _ptr;
50     }
51 protected:
52     void _AddRef()
53     {
54         ++(*_pCount);
55     }
56     void _Release()
57     {
58         if (--(*_pCount) == 0)
59         {
60             delete _ptr;
61             delete _pCount;
62             _ptr = NULL;
63             _pCount = NULL;
64         }
65     }
66 private:
67     T* _ptr;
68     int* _pCount;
69 };

引用計數是用指針來實現的,一開始采用的是靜態變量,但是有個問題,當聲明

1 SharedPtr<int> s = new int(20);
2 SharedPtr<int> s1=new int (30);

因為存儲的數值不同,引用計數應該是不會增長的,但是由於采用了靜態變量,該類對象都使用了這個引用計數,就會都往引用計數上加,這就錯了

采用指針,開辟出獨有的一塊空間來管理計數顯然才是我們所需要的,析構的時候把delete掉的指針賦空會更好~所以有了Release函數

應該在構造函數之前加上explicit關鍵字,是為了防止將指針經過轉換構造函數變成智能指針,就是防止 int *ptr; autoptr<int> a; a=ptr; 這樣的轉換發生

Copyright © Linux教程網 All Rights Reserved