看到了迭代器這裡,想到了應該把智能指針的知識總結一下了
我實現了三種智能指針,分別是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 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 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就對了
1 #include<iostream>
2 using namespace std;
3 template<class T>
4 class SharedPtr
5 {
6 public:
7 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函數