shared_ptr
1
| template< class T > class shared_ptr; (C++11 起)
|
多个shared_ptr管理同一个指针,仅当最后一个shared_ptr析构时,指针才被delete。这是怎么实现的呢?答案是:引用计数(reference counting)。引用计数指的是,所有管理同一个裸指针(raw pointer)的shared_ptr,都共享一个引用计数器,每当一个shared_ptr被赋值(或拷贝构造)给其它shared_ptr时,这个共享的引用计数器就加1,当一个shared_ptr析构或者被用于管理其它裸指针时,这个引用计数器就减1,如果此时发现引用计数器为0,那么说明它是管理这个指针的最后一个shared_ptr了,于是我们释放指针指向的资源。
shared_ptr的简单实现
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
| #include<iostream> #include<mutex> #include<thread> using namespace std;
template<class 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 (this != &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; };
|
错误用法
1. 循环引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| struct ListNode { int _data; shared_ptr<ListNode> _prev; shared_ptr<ListNode> _next; ~ListNode(){ cout << "~ListNode()" << endl; } }; int main() { shared_ptr<ListNode> node1(new ListNode); shared_ptr<ListNode> node2(new ListNode); cout << node1.use_count() << endl; cout << node2.use_count() << endl; node1->_next = node2; node2->_prev = node1; cout << node1.use_count() << endl; cout << node2.use_count() << endl; system("pause"); return 0; }
|
解决方案:在引用计数的场景下,把节点中的_prev和_next改成weak_ptr就可以了
2. 多个无关的shared_ptr管理同一裸指针
只能通过复制构造或复制赋值其值给另一 shared_ptr ,将对象所有权与另一 shared_ptr 共享。用另一 shared_ptr 所占有的底层指针创建新的 shared_ptr 导致未定义行为。
1 2 3
| int *a = new int; std::shared_ptr<int> p1(a); std::shared_ptr<int> p2(a);
|
3. 直接用new构造多个shared_ptr作为实参
1 2 3 4
| // 声明 void f(A *p1, B *p2); // 使用 f(new A, new B); <-- ×
|
1 2 3 4
| // 声明 void f(shared_ptr<A> p1, shared_ptr<B> p2); // 使用 f(shared_ptr<A>(new A), shared_ptr<B>(new B)); <-- √
|
tips
- 用shared_ptr,不用new
- 使用weak_ptr来打破循环引用
- 用make_shared来生成shared_ptr
ref
blog: http://www.oneyearago.me