本文最后更新于:2021年4月12日 晚上
实现 share_ptr
参考:面试题:简单实现一个shared_ptr智能指针
shared_ptr的原理:是通过引用计数的方式来实现多个shared_ptr对象之间共享资源。
- shared_ptr在其内部,给每个资源都维护了着一份计数,用来记录该份资源被几个对象共享。
- 在对象被销毁时(也就是析构函数调用),就说明自己不使用该资源了,对象的引用计数减一。
- 如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源;
- 如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指针了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| #include<iostream> #include<mutex> #include<thread> using namespace std;
template<typename T> class Shared_Ptr{ public: Shared_Ptr(T* ptr = nullptr) : _pPtr(ptr) , _pRefCount(new int(1)) , _pMutex(new mutex) {} ~Shared_Ptr() { Release(); } Shared_Ptr(const Shared_Ptr<T>& sp) : _pPtr(sp._pPtr) , _pRefCount(sp._pRefCount) , _pMutex(sp._pMutex) { AddRefCount(); } Shared_Ptr<T>& operator=(const Shared_Ptr<T>& sp) { if (_pPtr != sp._pPtr) { Release(); _pPtr = sp._pPtr; _pRefCount = sp._pRefCount; _pMutex = sp._pMutex; AddRefCount(); } return *this; } T& operator*(){ return *_pPtr; } T* operator->(){ return _pPtr; } int UseCount() { return *_pRefCount; } T* Get() { return _pPtr; } void AddRefCount() { _pMutex->lock(); ++(*_pRefCount); _pMutex->unlock(); } private: void Release() { bool deleteflag = false; _pMutex->lock(); if (--(*_pRefCount) == 0) { delete _pRefCount; delete _pPtr; deleteflag = true; } _pMutex->unlock(); if (deleteflag == true) delete _pMutex; } private: int *_pRefCount; T* _pPtr; mutex* _pMutex; };
|
shared_ptr的线程安全问题
- 智能指针对象中引用计数是多个智能指针对象共享的,两个线程中智能指针的引用计数同时++或- –,这个操作不是原子的,引用计数原来是1,++了两次,可能还是2。这样引用计数就错乱了。会导致资源未释放或者程序崩溃的问题。所以只能指针中引用计数++、- - 是需要加锁的,也就是说引用计数的操作是线程安全的。
- 智能指针管理的对象存放在堆上,两个线程中同时去访问,会导致线程安全问题。
- 虽然引用计数部分使用了原子操作进行修改,但shared_ptr的操作包括对象指针的赋值与引用计数的修改两部分,所以不是线程安全的;