数据结构库——智能指针的实现(下)

1,SmartPointer 被设计成每次只允许一个智能指针对象指向一片堆空间,也就限制了智能指针的运用,不能够运用于LinkList;

  

2,本节完成 SharedPointer 的具体实现:

 

3,SharedPointer 设计要点:

       1,类模板:

              1,通过计数机制(ref)标识堆空间;

                     1,堆内存被指向时:ref++;

                     2,指针被置空时:ref--;

                     3,ref == 0 时:释放堆内存;          

4,计数机制原理剖析:

      

       1,计数变量和堆空间对象生命周期完全一样,且都在堆空间中声明的;

      

5,SharedPointer 类的声明:

       

      

6,智能指针比较:

       1,由于 SharedPointer 支持多个对象同时指向一片堆空间,因此必须支持比较操作;

 

7,SharedPointer 智能指针的实现:

  1 #ifndef SHAREDPOINTER_H
  2 #define SHAREDPOINTER_H
  3 
  4 #include "Pointer.h"
  5 #include <cstdlib>
  6 #include "Exception.h"
  7 
  8 namespace DTLib
  9 {
 10 
 11 template <typename T>
 12 class SharedPointer : public Pointer<T>
 13 {
 14 protected:
 15    int* m_ref;  // 指向堆空间的计数变量,和对象相关联且同生命周期;
 16 
 17     void assign(const SharedPointer<T>& obj)
 18     {
 19         this->m_ref = obj.m_ref;
 20         this->m_pointer = obj.m_pointer;
 21 
 22         if( this->m_ref )  // obj 也可能为空;
 23         {
 24             (*this->m_ref)++;  
 25         }
 26    }
 27 
 28 public:
 29    SharedPointer(T* p = NULL) : m_ref(NULL)  // 用初始化列表来初始化成员变量;调用时用堆空间指针来初始化参数 p
 30     {
 31         if( p )
 32         {
 33             this->m_ref = static_cast<int*>(std::malloc(sizeof(int)));  // 申请堆空间给计数指针指向
 34 
 35             if( this->m_ref )
 36             {
 37                 this->m_pointer = p;
 38 
 39                 *(this->m_ref) = 1;  // 这里不能为 *(this->m_ref)++;,因为里面是随机值,而如果重新申请,则必然首先为 1,++只是为了后来的拷贝赋值而准备的;
 40             }
 41             else
 42             {
 43                 THROW_EXCEPTION(NoEnoughMemoryException, "No memory to creat SharedPointer object ...");
 44             }
 45         }
 46    }
 47 
 48     SharedPointer(const SharedPointer<T>& obj) : Pointer<T>(NULL)  // 初始化赋值调用,这里为了消除警告所以显示调用父类构造函数
 49     {
 50         assign(obj);
 51    }
 52 
 53    SharedPointer<T>& operator= (const SharedPointer<T>& obj)// 由于 SharedPointer 支持多个对象同时指向一片堆空间,因此必须支持比较操作;
 54    {
 55         if( this != &obj)
 56         {
 57             clear();  // 当前指针可能指向了别的对象,所以赋值前先让其不再指向别的对象,先清空,这样避免指向的别的对象的内存泄漏;
 58             assign(obj);
 59         }
 60 
 61         return *this;
 62    }
 63 
 64     void clear()  // 将当前指针置为空;
 65     {
 66         int* ref = this->m_ref;
 67         T* toDel = this->m_pointer;
 68         this->m_ref = NULL;
 69         this->m_pointer = NULL;
 70 
 71         if( ref )
 72         {
 73             (*ref)--;  // 不再指向的时候,要处理对象的计数;
 74 
 75             if( *ref == 0 )
 76             {
 77                 free(ref);  // 释放计数变量指向的空间;
 78                 delete toDel;  // 释放堆空间;
 79             }
 80         }
 81    }
 82 
 83     ~SharedPointer()
 84     {
 85         clear();
 86     }
 87 };
 88 
 89 /* 通过全局函数的方式来重载相等操作符 */
 90 template <typename T>
 91 bool operator== (const SharedPointer<T>& l, const SharedPointer<T>& r)
 92 {
 93     return (l.get() == r.get());  // 指向的堆空间是一个则相等;
 94 }
 95 
 96 /* 通过全局函数的方式来重载不等操作符 */
 97 template <typename T>
 98 bool operator!= (const SharedPointer<T>& l, const SharedPointer<T>& r)
 99 {
100     return !(l == r); // 不相等操作符重载使用相等操作符来实现;
101 }
102 
103 }
104 
105 #endif // SHAREDPOINTER_H

 

8,SharedPointer 的测试代码:

 1 #include <iostream>
 2 #include "SharedPointer.h"
 3 
 4 using namespace std;
 5 using namespace DTLib;
 6 
 7 class Test : public Object
 8 {
 9 public:
10    int value;
11 
12     Test() : value(0)
13     {
14         cout << "Test()" << endl;
15    }
16 
17     ~Test()
18     {
19         cout << "~Test()" << endl;
20     }
21 };
22 
23 int main()
24 {
25     SharedPointer<Test> sp0(new Test());
26     SharedPointer<Test> sp1 = sp0;
27    SharedPointer<Test> sp2 = NULL;
28 
29     sp2 = sp1;
30    sp2->value = 100;
31 
32     cout << sp0->value << endl;
33     cout << sp1->value << endl;
34     cout << sp2->value << endl;
35    cout << (sp0 == sp1) << endl;
36 
37    sp2.clear();
38 
39     cout << (sp0 == sp2) << endl;
40     const SharedPointer<Test> sp3 = new Test();
41    sp3->value = 100;
42 
43     return 0;
44 }

 

9,智能指针使用军规:

       1,智能用来指向堆空间中的单个变量(对象);

       2,不同类型的智能指针对象不能混合使用;

       3,不要使用 delete 释放智能指针指向的堆空间;

      

10,小结:

       1,SharedPointer 最大程度的模拟了原生指针的行为;

       2,计数机制确保多个智能指针合法的指向同一片堆空间;

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

       4,不同类型的智能指针不要混合使用;

       5,堆对象的生命周期由智能指针进行管理;

posted @ 2019-05-25 15:57 子宇24 阅读(...) 评论(...) 编辑 收藏