智能指针之 shared_ptr
std::shared_ptr
是通过指针保持对象共享所有权的智能指针。多个 shared_ptr
对象可占有同一对象大概实现了一下,主要实现原理为,共享指针内部持有堆资源
的指针以及引用计数的指针,通过对这两个指针的维护,达到多个共享对象对同一资源的控制
实现主要分为三个文件。share_ptr.h,smart_ptr_define.h, main.cpp (编译平台:Linux centos 7.0 编译器:gcc 4.8.5 )
- 1 //smart_ptr_define.h
- 2 #ifndef __SMART_PTR_DEFINE_H__
- 3 #define __SMART_PTR_DEFINE_H__
- 4
- 5 #include <assert.h>
- 6
- 7 #define PTR_ASSERT(x) assert(x)
- 8
- 9 #define _SMART_PTR_BEGIN namespace smartptr {
- 10 #define _SMART_PTR_END }
- 11 #define _SMART_PTR ::smartptr::
- 12
- 13 #endif
主要实现文件share_ptr.h
- 1 #ifndef __SHARE_PTR_H__
- 2 #define __SHARE_PTR_H__
- 3
- 4 #include <iostream>
- 5 #include "smart_ptr_define.h"
- 6
- 7 _SMART_PTR_BEGIN
- 8
- 9 template <class T>
- 10 struct default_deleter
- 11 {
- 12 void operator()(T* ptr)
- 13 {
- 14 if (ptr != NULL)
- 15 {
- 16 delete ptr;
- 17 ptr = NULL;
- 18 }
- 19 }
- 20 };
- 21
- 22 template <class T, class deleter = default_deleter<T> >
- 23 class shared_ptr
- 24 {
- 25 public:
- 26 typedef shared_ptr<T, deleter> SHARE_PTR;
- 27
- 28 shared_ptr()
- 29 {
- 30 m_ptr = NULL;
- 31 m_iRefCount = NULL;
- 32 }
- 33
- 34 explicit shared_ptr(T* ptr)
- 35 {
- 36 if (ptr != NULL)
- 37 {
- 38 m_ptr = ptr;
- 39 RefCountInit();
- 40 }
- 41 }
- 42
- 43 shared_ptr(deleter d, T* ptr)
- 44 {
- 45 if (ptr != NULL)
- 46 {
- 47 m_ptr = ptr;
- 48 m_deleter = d;
- 49 RefCountInit();
- 50 }
- 51 }
- 52
- 53 //拷贝构造
- 54 shared_ptr(const SHARE_PTR& sh_ptr)
- 55 {
- 56 if (sh_ptr.m_ptr != NULL)
- 57 {
- 58 m_ptr = sh_ptr.m_ptr;
- 59 m_deleter = sh_ptr.m_deleter;
- 60 m_iRefCount = sh_ptr.m_iRefCount;
- 61
- 62 RefCountIncrease();
- 63 }
- 64 }
- 65
- 66 //赋值运算符
- 67 SHARE_PTR& operator = (const SHARE_PTR& sh_ptr)
- 68 {
- 69 if (this != &sh_ptr)
- 70 {
- 71 RefCountDecrease();
- 72
- 73 if (sh_ptr.m_ptr != NULL)
- 74 {
- 75 m_ptr = sh_ptr.m_ptr;
- 76 m_deleter = sh_ptr.m_deleter;
- 77 m_iRefCount = sh_ptr.m_iRefCount;
- 78
- 79 RefCountIncrease();
- 80 }
- 81 }
- 82
- 83 return (*this);
- 84 }
- 85
- 86 ~shared_ptr()
- 87 {
- 88 RefCountDecrease();
- 89 }
- 90
- 91 public:
- 92 //提领操作
- 93 T& operator*()
- 94 {
- 95 PTR_ASSERT(m_ptr != NULL);
- 96 return *(m_ptr);
- 97 }
- 98
- 99 //原始指针操作
- 100 T* operator->()
- 101 {
- 102 PTR_ASSERT(m_ptr != NULL);
- 103 return m_ptr;
- 104 }
- 105
- 106 operator bool() const
- 107 {
- 108 return m_ptr != NULL;
- 109 }
- 110
- 111 //取得原始指针
- 112 T* getPointer()
- 113 {
- 114 PTR_ASSERT(m_ptr != NULL);
- 115 return m_ptr;
- 116 }
- 117
- 118 //获得引用计数
- 119 int getRefCount()
- 120 {
- 121 PTR_ASSERT(m_iRefCount != NULL);
- 122 return *m_iRefCount;
- 123 }
- 124
- 125
- 126 private:
- 127 void RefCountInit()
- 128 {
- 129 m_iRefCount = new int(1);
- 130 }
- 131
- 132 void RefCountIncrease()
- 133 {
- 134 if (m_iRefCount != NULL)
- 135 {
- 136 ++(*m_iRefCount);
- 137 }
- 138 }
- 139
- 140 void RefCountDecrease()
- 141 {
- 142 if (m_iRefCount != NULL && --(*m_iRefCount) == 0)
- 143 {
- 144 m_deleter(m_ptr);
- 145 delete m_iRefCount;
- 146 m_ptr = NULL;
- 147 m_iRefCount = NULL;
- 148 }
- 149 }
- 150
- 151 private:
- 152 int* m_iRefCount; //引用计数
- 153
- 154 T* m_ptr; //对象指针
- 155
- 156 deleter m_deleter; //删除器
- 157 };
- 158
- 159 _SMART_PTR_END
- 160 #endif // !__SHARE_PTR_H__
main函数测试
- 1 #include "share_ptr.h"
- 2 #include <memory>
- 3
- 4 class Test
- 5 {
- 6 public:
- 7 Test()
- 8 {
- 9 std::cout << "construct.." << std::endl;
- 10 }
- 11
- 12 void method()
- 13 {
- 14 std::cout << "welcome Test.." << std::endl;
- 15 }
- 16
- 17 ~Test()
- 18 {
- 19 std::cout << "destruct.." << std::endl;
- 20 }
- 21 };
- 22
- 23 int main()
- 24 {
- 25 Test* t1 = new Test();
- 26
- 27 _SMART_PTR shared_ptr<Test> shptr(t1);
- 28
- 29 _SMART_PTR shared_ptr<Test> shptr1(shptr);
- 30
- 31 _SMART_PTR shared_ptr<Test> shptr2 = shptr1;
- 32
- 33 std::cout << "RefCount: " << shptr2.getRefCount() << std::endl;
- 34
- 35 shptr2->method();
- 36
- 37 (*shptr2).method();
- 38
- 39 if (shptr2)
- 40 {
- 41 std::cout << "ptr is exit " << std::endl;
- 42 }
- 43
- 44
- 45
- 46 return 0;
- 47 }
测试最后打印:
- 1 [yejy@yejy cmake-00]$ ./smartptr
- 2 construct..
- 3 RefCount: 3
- 4 welcome Test..
- 5 welcome Test..
- 6 ptr is exit
- 7 destruct..
- 8 [yejy@yejy cmake-00]$
shared_ptr主要需实现的功能点如下(以下总结引用自网络,非原创):
-
没有参数构造的时候,初始化为空,即对象和引用计数的两个指针都为0
-
使用指针为参数构造时,拥有此指针,在没有智能指针指向它时进行析构
-
智能指针复制时,两个智能指针共同拥有内部指针,引用计数同时+1
-
智能指针可以使用智能指针或普通指针重新赋值。重载=操作符,对于智能指针赋值,需要考虑是否自赋值,以避免将自身析构了后再重新赋值,而普通指针赋值给智能指针,则不需要考虑自赋值,因为两者本身是两个类型
-
获得底层指针的访问,定义
getPtrPointer()
和getPtrCounter()
来分别返回底层指针和引用计数,定义operator bool()
来处理智能指针隐式转换为bool
的情况 -
重载
->
和×
操作符 ,来实现与普通指针相同的指针访问 -
需要支持隐式指针类型转换,
static_cast
不支持而dynamic_cast
支持的转换则使用Cast<T2>()
成员函数来解决。考虑定义友元类,以防止指向派生类的智能指针有权限访问基类的内部对象;当转型不成功时,返回为空 (未实现) -
如果一个裸指针直接用来创建两个智能指针的话,期望的情况是当两个智能指针析构掉的时候,该指针会被delete两次从而崩溃(这是
shared_ptr
的特点) -
不处理循环引用(也是
shared_ptr
的特点),可以通过与weak_ptr
协作来打破循环 -
实现
deleter
机制