C++中的智能指针实现

1,本文介绍智能指针,为了避免内存泄漏问题;

 

2,永恒的话题,内存泄漏(臭名昭著的 Bug ):

    1,动态申请堆空间,用完后不归还;

    2,C++ 语言中没有垃圾回收的机制;

       1,Java、C# 语言中都引入了垃圾回收机制,定期检测内存,发现没有使用,则回收;

       2,垃圾回收机制可以很好的避免内存泄漏;

       3,C++ 中的动态内存申请和归还完全依赖开发者,所以必然会出错;

           1,大型软件公司采用编码流程和代码规范,来解决包括内存泄漏的问题;

           2,提交代码需要小组内部人员审核代码是否准许了编码流程和代码规范,效率低下,也包括熟读代码规范;

           3,效率低下,产品上市受影响;

    3,指针无法控制所指堆空间的生命周期;

       1,操作动态内存空间的时候,都是基于指针,而指针就是一个变量,指针可以指向动态空间,但是却不能够控制动态内存空间的生命周期;

       2,也就是指针和动态内存空间没有必然联系,指针变量销毁了,动态内存空间还可以存在;

       3,上述两点就是本质问题;

      

3,内存泄漏编程实验:

    1,main.cpp 文件:

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class Test
 7 {
 8     int i;
 9 public:
10     Test(int i)
11     {
12         this->i = i;
13     }
14     int value()
15     {
16         return i;
17     }
18     ~Test()
19     {
20     }
21 };
22 
23 int main()
24 {
25     for(int i=0; i<5; i++)
26     {
27         Test* p = new Test(i); //p 指向堆空间,但是下面没有归还,同时 p 是一个局部变量,for 循环结束后就销毁了,但是所指向的堆空间并没有销毁,没人可以使用这片空间,内存就泄漏了;
28         
29         cout << p->value() << endl;
30     }
31     
32     return 0;
33 }

   

4,深度分析,我们需要什么:

    1,需要一个特殊的指针;

       1,智能指针对象,通过类的普通构造函数完成;

    2,指针生命周期结束时主动释放堆空间;

       1,这是最主要的一点,通过类的析构函数完成;

    3,一片堆空间最多只能由一个指针标识;

       1,避免多次释放内存,通过拷贝构造函数和赋值操作符完成;

    4,杜绝指针运算和指针比较;

       1,杜绝指针运算可以避免指针越界和野指针;

       2,上面的第三个需求都满足了,指针比较就没有意义了;

       3,通过不重载类的运算符自行完成;

   

5,智能指针分析:

    1,解决方案:

        1,重载指针特征操作符(-> 和 *);

             1,通过操作符重载模拟指针的行为;

             2,定义一个对象,让这个对象通过操作符重载模拟真正的指针行为;

             3,-> 和 * 是 C++ 中的操作符,所以我们必然可以重载;

             4,遵循下面三点重载规则;

        2,只能通过类的成员函数重载;

             1,能切仅能通过类的成员函数重载;

        3,重载函数不能使用参数;

             1,两者都是单目运算符;

        4,只能定义一个重载函数;

             1,和第三点是一件事;

    2,通过指针的特征操作符来使用对象替代指针,这个对象  就称为智能指针, 或者通过类对象模拟指针的行为,这个类对象称为智能指针;

    3,智能指针编程实验:

        1,main.cpp 文件:

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class Test
 7 {
 8     int i;
 9 public:
10     Test(int i)
11     {
12         cout << "Test(int i)" << endl;
13         this->i = i;
14     }
15     int value()
16     {
17         return i;
18     }
19     ~Test()
20     {
21         cout << "~Test()" << endl;
22     }
23 };
24 
25 class Pointer
26 {
27     Test* mp;
28 public:
29     /* 满足需求分析的第一点 */
30     Pointer(Test* p = NULL)
31     {
32         mp = p;
33     }
34 
35    /* 以下两个函数做了需求分析的第三点 */ 
36 
37     Pointer(const Pointer& obj)
38     {
39       // delete mp; // 还在拷贝构造,这个时候 mp 还是野指针;
40         mp = obj.mp;  // 传递堆空间的控制; 
41         const_cast<Pointer&>(obj).mp = NULL;//初始化对象不管之前的;堆空间了,做所有权的转移,保证堆空间最多只能由一个对象被标识;
42     }
43     Pointer& operator = (const Pointer& obj)
44     {
45         if( this != &obj )
46         {
47             delete mp;
48             mp = obj.mp;
49             const_cast<Pointer&>(obj).mp = NULL;
50         }
51         
52         return *this;
53     }
54     Test* operator -> ()  // 返回指针,准备指示;
55     {
56         return mp;
57     }
58     Test& operator * ()  // 解引用,返回对象;
59     {
60         return *mp;
61     }
62     bool isNull()
63     {
64         return (mp == NULL);
65     }
66     ~Pointer()   // 释放成员指针指向的堆空间,需求分析的第二点;
67     {
68         delete mp;
69     }
70 };
71 
72 int main()
73 {
74     Pointer p1 = new Test(0);  // ==> Test* p1 = new Test(0);
75     
76     cout << p1->value() << endl;
77     
78     Pointer p2 = p1;  // 这里对象拷贝构造函数;
79     
80     cout << p1.isNull() << endl;
81     
82     cout << p2->value() << endl;
83     
84     return 0;
85 }

   2,输出结果:

1 Test(int i)

2 0

3 1

4 0

5 ~Test() 

        3,智能指针没有定义对象运算和对象比较的操作符,所以就满足了需求分         析的第四点;

    4,智能指针使用军规:

        1,只能用来指向堆空间中的对象或者变量;

        (2),不能使用智能指针指向栈空间中的对象;

      

6,小结:

    1,指针特征操作符(-> 和 *)可以被重载;

    2,重载指针特征符能够使对象代替指针;

    3,智能指针只能用于指向堆空间中的内存;

    4,智能指针的意义在于最大程度的避免内存问题;

       1,使用智能指针代替 C 中的原生指针,这是智能指针的工程意义;

猜你喜欢

转载自www.cnblogs.com/dishengAndziyu/p/10913800.html