第37课 智能指针分析(指针特征操作符( -> 、 *)重载)

1. 永恒的话题:内存泄漏

(1)动态申请堆空间用完后不归还

(2)C++语言中没有垃圾回收的机制

(3)指针无法控制所指堆空间的生命周期------------指针是变量,可以指向内存堆空间,但是无法控制所指堆空间的生命周期

说明内存泄漏:

 1 #include<iostream>
 2 #include<string>
 3 
 4 using namespace std;
 5 
 6 class Test
 7 {
 8     int i;
 9 
10 public:
11 
12     Test(int i)
13     {
14         this->i = i;
15     }
16 
17     int value()
18     {
19         return i;
20     }
21 
22     ~Test()
23     {
24     }
25 };
26 
27 int main()
28 {
29     for (int i = 0; i < 5; i++)
30     {
31         Test* p = new Test(i); //P指向堆空间的对象 
32                                //指针是局部变量for()循环之后消失,但是指针开辟的空间没有进行释放  内存泄漏
33                                //长时间运行会出现Bug
34 
35         cout << p->value() << endl;
36 
37     }
38 
39     return 0;
40 }

2. 深度的思考:我们需要什么?

(1)需要一个特殊的指针指针生命期结束时主动释放堆空间

(2)一片堆空间最多只能由一个指针来标识------------避免内存多次释放

(3)杜绝指针运算指针比较-----------因为只有一个该类对象的指针能指向堆空间,避免指针越界,野指针

3. 解决方案

定义一个对象,让对象取模拟真正意思上的指针行为---------对象代替指针,称该对象为智能指针 -------智能指针本质:是个对象

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

(2)只能通过类的成员函数重载

(3)重载函数不能使用参数

(4)只能定义一个重载函数

(5)注意:智能指针只能用来指向堆空间中的对象或变量(不能指向栈)

实验:(1)实现特殊的指针指针生命期结束时主动释放堆空间

 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 
14         this->i = i;
15     }
16     int value()
17     {
18         return i;
19     }
20     ~Test()
21     {
22         cout << "~Test ()" << endl;
23     }
24 
25 };
26 
27 
28 //智能指针  本质是对象--------首先创建智能指针类
29 class Pointer
30 {
31     Test* mp;              //指针mp指向对象Test,用于保存要被管理对象的指针
32 
33 public:
34 
35     //构造函数被堆空间上内存地址初始化
36 
37     Pointer(Test* p = NULL)   //指针被堆空间上的地址初始化---参数Test*指针
38     {
39         mp = p;
40     }
41 
42     //重载->操作符
43 
44     Test* operator -> ()    //不能使用参数,所以也就只能定义一个重载函数
45     {
46         return mp;             //返回成员指针
47     }
48 
49     //重载*操作符  
50 
51     Test& operator * ()    //不能使用参数,所以也就只能定义一个重载函数
52     { 
53         return *mp;        //*作用指针意义:返回当前指针所指变量或对象
54     }
55 
56     ~Pointer()
57     {
58         delete mp;     //智能指针被析构时,同时删除其所管理的Test类的对象,释放成员指针指向的堆空间
59     }
60 };
61 
62 int main()
63 {
64     for (int i = 0; i < 5; i++)
65     {
66         //    Test* p = new Test(i);   //那么就可以用类对象名代替指针     
67 
68         Pointer p = new Test(i);     //可以动态的将申请的空间释放
69 
70         cout << p->value() << endl;  //01234
71           
72     }
73     return 0;
74 }

实现:一片堆空间最多只能由一个指针来标识------------避免内存多次释放

    不进行指针运算和比较

    方法:重载赋值操作符和拷贝构造

  1 #include<iostream>
  2 #include<string>
  3 
  4 //智能指针  本质是对象
  5 using namespace std;
  6 
  7 class Test
  8 {
  9     int i;
 10 public:
 11     Test(int i)
 12     {
 13         cout <<"Test (int i)"<< endl;
 14         this->i = i;
 15     }
 16     int value()
 17     {
 18         return i;
 19     }
 20     ~Test()
 21     {
 22         cout << "~Test (int i)" << endl;
 23     }
 24 
 25 };
 26 
 27 class Pointer
 28 {
 29     Test* mp;    //数据成员为指针
 30 
 31 public:
 32 
 33     Pointer(Test* p = NULL)    //构造函数被堆空间上内存地址初始化
 34     {
 35         mp = p;
 36     }
 37 
 38 
 39     // 实现一片堆空间最多只能由一个指针标识   杜绝多次释放
 40 
 41     //拷贝构造函数
 42     Pointer(const Pointer& obj)                                         //自定义深拷贝构造函数
 43     {
 44      //   delete mp;        //拷贝构造阶段,mP野指针不能删除---内存错误
 45 
 46         mp = obj.mp;      //当前对象的成员指针mp指向初始化对象的成员指针所对应的堆空间---两个指针指向一片内存空间
 47                           //初始化对象把他指向的堆空间完全交给当前对象-----------即保证只有一个智能指针指向同一片内存
 48 
 49         const_cast<Pointer&>(obj).mp = NULL;  //所有权的传递,自己置空  const_cast去除只读属性
 50     }
 51 
 52 
 53     //赋值操作符重载函数 
 54     Pointer& operator=(const Pointer& obj)  // 1,返回值类型一定是引用Test&为了连续赋值   2,参数是const引用类型
 55     {
 56         //进行赋值操作
 57         if (this != &obj)     //3,赋值操作符不是自赋值a=a,要避免赋值,通过This判断,this指向当前对象的地址和参数地址不同才进行赋值操作
 58         {
 59             delete mp;
 60 
 61             mp = obj.mp;     //保证赋值操作时,只能由一个智能指针指向同一堆空间
 62 
 63             const_cast<Pointer&>(obj).mp = NULL;
 64         }
 65         return *this;     //4,返回当前对象地址
 66     }
 67 
 68     //重载指针特征操作符
 69     Test* operator -> ()
 70     {
 71         return mp;    //返回成员指针
 72     }
 73     Test& operator * ()
 74     {
 75         return *mp;    //返回当前指针所指变量或对象
 76     }
 77 
 78     bool isNull()     //判断当前智能指针是否为空
 79     {
 80         return(mp == NULL);
 81     }
 82 
 83     ~Pointer()
 84     {
 85         delete mp;
 86     }
 87 };
 88 
 89 int main()
 90 {
 91     Pointer p1 = new Test(0);  //定义智能指针P1
 92 
 93     cout << p1->value() << endl;   //0
 94 
 95     Pointer p2 = p1;          //定义智能指针P2,用p1进行初始化,p1管理的堆空间转给P2
 96 
 97     //不能指针比较的指针运算
 98 //    p2++;              
 99 //    if(p1==p2)         
100 
101     cout << p1.isNull() << endl;   //1空 p1指向NULL,不再指向原来的堆空间
102 
103     cout << p2->value() << endl;   //0   p2接管P1指向的堆空间------管理92行堆对象
104 
    //p2++;不重载++,因为每次只能一个智能指针指向堆空间,这种++操作没意义
  

       //p2智能指针生命期结束,会自动释放接管的堆空间
105 return 0; 106 }

//输出结果:

//Test(int i)

//5

//1

//5

//~Test()

存在问题: 智能指针对应的类只能指向Test固定的类类型,不能指向其他类型,能不能指向各类他能管理的类类型------以后会学到模板实现

4. 小结

      掌握智能指针的创建

   智能指针在自己生命周期结束,自动释放所指的内存空间

   要求c++避免使用原生指针,那么以后就可以使用智能指针

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

(2)重载指针特征符能够使用对象代替指针

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

(4)智能指针意义在于最大程度避免内存问题

猜你喜欢

转载自www.cnblogs.com/liuyueyue/p/13382019.html