1. 程式人生 > >C++ 智能指針學習

C++ 智能指針學習

release new div str 我們 指針的引用 機制 cin 轉化

C++ Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/*
SmartPtr.cpp
Author: Michael Joessy
Date: 2017-06-07
Marks: C++裏面的四個智能指針: auto_ptr, shared_ptr, weak_ptr, unique_ptr;
其中後三個是C++11支持,並且第一個已經被C++11棄用。

為什麽要使用智能指針:
我們知道C++的內存管理是讓很多人頭疼的事,當我們寫一個new語句時,一般就會立即把delete語句直接也寫了;
但是我們不能避免程序還未執行到delete時就跳轉了或者在函數中沒有執行到最後的delete語句就返回了;
如果我們不在每一個可能跳轉或者返回的語句前釋放資源,就會造成內存泄露。
使用智能指針可以很大程度上的避免這個問題:
因為智能指針就是一個類,當超出了類的作用域是,類會自動調用析構函數,析構函數會自動釋放資源。
*/


#include <memory>
#include <iostream>
#include <string>

using namespace std;
using namespace std::tr1;

//auto_ptr http://www.cplusplus.com/reference/memory/auto_ptr/
//unique_ptr http://www.cplusplus.com/reference/memory/unique_ptr/
//share_ptr http://www.cplusplus.com/reference/memory/share_ptr/
//weak_ptr http://www.cplusplus.com/reference/memory/weak_ptr/
class TestSmartPtr
{
public:
TestSmartPtr(string str)
{
m_str = str;
cout <<
"TestSmartPtr creat\n";
}
~TestSmartPtr()
{
cout <<
"TestSmartPtr delete:" << m_str <<endl;
}
string& getStr()
{
return m_str;
}
void setStr(string str)
{
m_str = str;
}
void print()
{
cout << m_str << endl;
}
private:
string m_str;
};


class classB;
class classA
{
public:
//shared_ptr<classB> pB_;
weak_ptr<classB> pB_;
~classA()
{
cout <<
"classA delete\n";
}
};
class classB
{
public:
shared_ptr<classA> pA_;
~classB()
{
cout <<
"classB delete\n";
}
};


int main(void)
{
//auto_ptr
/*成員函數get()返回一個原始的指針,成員函數reset()重新綁定指向的對象,而原來的對象則會被釋放
判斷一個智能指針是否為空應該使用if(pTestAutoPtr.get() == NULL)
成員函數release()只是把智能指針賦值為空,但是它原來指向的內存並沒有被釋放,相當於它只是釋放了對資源的所有權
當我們想要在中途釋放資源,而不是等到智能指針被析構時才釋放,我們可以使用pTestAutoPtr.reset(); 語句。
*/

#if 0
auto_ptr<TestSmartPtr> pTestAutoPtr(
new TestSmartPtr("315"));
if(pTestAutoPtr.get() == NULL)
{
cout <<
"pTestAutoPtr = NULL\n";
}
pTestAutoPtr->setStr(
"Michael ");
pTestAutoPtr->print();
pTestAutoPtr.get()->print();
pTestAutoPtr->getStr() +=
"Joessy !";
(*pTestAutoPtr).print();
pTestAutoPtr.reset(
new TestSmartPtr("315"));
pTestAutoPtr->print();
pTestAutoPtr.release();
#endif
//unique_ptr
/*unique_ptr 是一個獨享所有權的智能指針,它提供了嚴格意義上的所有權,包括:
1、擁有它指向的對象
2、無法進行復制構造,無法進行復制賦值操作。即無法使兩個unique_ptr指向同一個對象。但是可以進行移動構造和移動賦值操作
3、保存指向某個對象的指針,當它本身被刪除釋放的時候,會使用給定的刪除器釋放它指向的對象
unique_ptr 可以實現如下功能:
1、為動態申請的內存提供異常安全
2、動態申請的內存所有權傳遞給某函數
3、從某個函數返回動態申請內存的所有權
4、在容器中保存指針
5、auto_ptr應該具有的功能
*/

#if 0
unique_ptr<
int> up(p);
unique_ptr<TestSmartPtr> pTestUniquePtr1(
new TestSmartPtr("123"));
unique_ptr<TestSmartPtr> pTestUniquePtr2(
new TestSmartPtr("456"));
pTestUniquePtr1->print();
pTestUniquePtr2 = std::move(pTestUniquePtr1);
//不能直接pTestUniquePtr2 = pTestUniquePtr1
if(pTestUniquePtr1 == NULL)
{
cout <<
"pTestUniquePtr1 = NULL\n";
}
TestSmartPtr* p = pTestUniquePtr2.release();
p->print();
pTestUniquePtr1.reset(p);
pTestUniquePtr1->print();
#endif
//share_ptr
/* 從share中就可以看出資源可以被多個指針共享,它使用計數機制來表明資源被幾個指針共享。
可以通過成員函數use_count()來查看資源的所有者個數。
除了可以通過new來構造,還可以通過傳入auto_ptr, unique_ptr,weak_ptr來構造。
當我們調用release()時,當前指針會釋放資源所有權,計數減一。
當計數等於0時,資源會被釋放。
*/

#if 0
shared_ptr<TestSmartPtr> pTestSharePtr1(
new TestSmartPtr("123"));
shared_ptr<TestSmartPtr> pTestSharePtr2(
new TestSmartPtr("456"));
cout << pTestSharePtr2->getStr()<<endl;
cout << pTestSharePtr2.use_count()<<endl;
pTestSharePtr1 = pTestSharePtr2;
//"456"引用次數加1,"123"銷毀
pTestSharePtr1->print();
cout << pTestSharePtr2.use_count() << endl;
cout << pTestSharePtr1.use_count() << endl;
pTestSharePtr1.reset();
pTestSharePtr2.reset();
//此時"456"銷毀
#endif
//weak_ptr
/*weak_ptr是用來解決shared_ptr相互引用時的死鎖問題;
如果說兩個shared_ptr相互引用,那麽這兩個指針的引用計數永遠不可能下降為0,資源永遠不會釋放。
它是對對象的一種弱引用,不會增加對象的引用計數,和shared_ptr之間可以相互轉化;
shared_ptr可以直接賦值給它,它可以通過調用lock函數來獲得shared_ptr。
*/

#if 0
shared_ptr<classB> pB(
new classB());
shared_ptr<classA> pA(
new classA());
pB->pA_ = pA;
pA->pB_ = pB;
cout << pB.use_count() << endl;
cout << pA.use_count() << endl;
#endif
/*說明:
pA與pB之間互相引用,兩個資源的引用計數為2;
當要跳出函數時,智能指針pA與pB析構時兩個資源引用計數會減一;
但是兩者引用計數還是為1,導致跳出函數時資源沒有被釋放(classA與classB的析構函數沒有被調用).

如果把其中一個改為weak_ptr就可以了,我們把類A裏面的shared_ptr<B> pB_; 改為weak_ptr<B> pb_;
這樣的話,資源classB的引用開始就只有1;
當pB析構時,B的計數變為0,B得到釋放;
B釋放的同時也會使A的計數減一;
同時pa析構時使A的計數減一,那麽A的計數為0,A得到釋放。
*/



cin.get();
return 0;
}

C++ 智能指針學習