图解shared_ptr共享智能指针原理分析
Posted kongyijin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图解shared_ptr共享智能指针原理分析相关的知识,希望对你有一定的参考价值。
shared_ptr共享智能指针
shared_ptr
是 C++ 标准库提供的智能指针类型之一,它用于管理动态分配的资源,并在多个指针之间共享所有权。
特点
- 共享所有权的智能指针。多个shared_ptr指向同一对象
- 可赋值构造(CopyConstructible)
- 可复制赋值(CopyAssignable)
- 数据访问非线程安全
- shared_ptr 的控制块是线程安全
应用场景
-
共享资源:当多个指针需要共享同一个资源时,可以使用
shared_ptr
。这种情况下,shared_ptr
会维护一个引用计数,跟踪有多少个指针指向相同的资源。只有当最后一个shared_ptr
被销毁时,资源才会被释放。 -
动态内存管理:
shared_ptr
可以用于管理动态分配的内存。它会自动跟踪资源的引用计数,当没有指针引用该内存时,自动释放内存,避免内存泄漏。 -
异常安全性:
shared_ptr
可以提供异常安全性。在函数中使用shared_ptr
管理资源时,即使发生异常,也可以确保资源的正确释放,避免资源泄漏。 -
循环引用的处理:在存在循环引用的情况下,使用
shared_ptr
可以解决内存泄漏的问题。shared_ptr
使用强引用计数,只有当引用计数为零时,才会释放资源,因此可以处理循环引用并正确释放相关资源。 -
STL 容器的元素:
shared_ptr
可以作为 STL 容器(如vector
、list
、map
等)中的元素类型,方便地管理容器中的动态分配对象。
需要注意的是,由于 shared_ptr
维护引用计数,它会带来一定的性能开销。当不需要共享所有权或资源生命周期可以明确控制时,可以考虑其他智能指针类型,如 unique_ptr
。
智能指针之 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 [[email protected] cmake-00]$ ./smartptr 2 construct.. 3 RefCount: 3 4 welcome Test.. 5 welcome Test.. 6 ptr is exit 7 destruct.. 8 [[email protected] 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
机制
以上是关于图解shared_ptr共享智能指针原理分析的主要内容,如果未能解决你的问题,请参考以下文章
c++复习笔记——智能指针详细解析(智能指针的使用,原理分析)