天天看點

C++ 智能指針學習

 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)

    void print()

        cout << m_str << endl;

private:

    string m_str;

};

class classb;

class classa

    //shared_ptr<classb> pb_;

    weak_ptr<classb> pb_;

    ~classa()

        cout << "classa delete\n";

class classb

    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.release();

#endif

    //unique_ptr

    /*unique_ptr 是一個獨享所有權的智能指針,它提供了嚴格意義上的所有權,包括:

    1、擁有它指向的對象

    2、無法進行複制構造,無法進行複制指派操作。即無法使兩個unique_ptr指向同一個對象。但是可以進行移動構造和移動指派操作

    3、儲存指向某個對象的指針,當它本身被删除釋放的時候,會使用給定的删除器釋放它指向的對象

    unique_ptr 可以實作如下功能:

    1、為動态申請的記憶體提供異常安全

    2、動态申請的記憶體所有權傳遞給某函數

    3、從某個函數傳回動态申請記憶體的所有權

    4、在容器中儲存指針

    5、auto_ptr應該具有的功能

    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);

    //share_ptr

    /* 從share中就可以看出資源可以被多個指針共享,它使用計數機制來表明資源被幾個指針共享。

    可以通過成員函數use_count()來檢視資源的所有者個數。

    除了可以通過new來構造,還可以通過傳入auto_ptr, unique_ptr,weak_ptr來構造。

    當我們調用release()時,目前指針會釋放資源所有權,計數減一。

    當計數等于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"銷毀

    //weak_ptr

    /*weak_ptr是用來解決shared_ptr互相引用時的死鎖問題;

    如果說兩個shared_ptr互相引用,那麼這兩個指針的引用計數永遠不可能下降為0,資源永遠不會釋放。

    它是對對象的一種弱引用,不會增加對象的引用計數,和shared_ptr之間可以互相轉化;

    shared_ptr可以直接指派給它,它可以通過調用lock函數來獲得shared_ptr。

    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;

    /*說明:

    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;

}

繼續閱讀