数据结构库——智能指针的实现(下)
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,堆对象的生命周期由智能指针进行管理;