RAII:利用对象生命周期来控制程序资源,在构造时获取资源,析构的时释放资源
auot_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
| template<class T> class AutoPtr { public: AutoPtr(T* ptr = nullptr) : _ptr(ptr) {} ~AutoPtr() { if (_ptr) delete _ptr; } AutoPtr(AutoPtr<T>& ap) : _ptr(ap._ptr) { ap._ptr = NULL; } AutoPtr<T>& operator=(AutoPtr<T>& ap) { if (this != &ap) { if (_ptr) delete _ptr; _ptr = ap._ptr; ap._ptr = NULL; } return *this; } T& operator*() { return *_ptr; } T* operator->() { return _ptr; } private: T* _ptr; };
|
Bug:
1 2
| AutoPtr<T> ap(new T); AutoPtr<T> copy(ap);
|
所以auto_ptr根本用不了
C++11 unique_ptr
也叫scoped_ptr(boost库)
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
| template<class T> class UniquePtr { public: UniquePtr(T* ptr = nullptr) : _ptr(ptr) {}
~UniquePtr() { if (_ptr) delete _ptr; }
T& operator*() { return *_ptr; } T* operator->() { return _ptr; } private: UniquePtr(UniquePtr<T> const &) = delete; UniquePtr & operator=(UniquePtr<T> const &) = delete; private: T * _ptr; }
|
相比auto_ptr,简单粗暴的防拷贝,勉强可以使用,但没有从根本解决问题
C++11 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
| template <class T> class SharedPtr { public: SharedPtr(T* ptr = nullptr) : _ptr(ptr) , _pRefCount(new int(1)) , _pMutex(new mutex) {}
~SharedPtr() { Release(); }
SharedPtr(const SharedPtr<T>& sp) : _ptr(sp._ptr) , _pRefCount(sp._pRefCount) , _pMutex(sp._pMutex) { AddRefCount(); }
SharedPtr<T>& operator=(const SharedPtr<T>& sp) { if (_ptr != sp._ptr) { Release(); _ptr = sp._ptr; _pRefCount = sp._pRefCount; _pMutex = sp._pMutex; AddRefCount(); } return *this; }
T& operator*() { return *_ptr; } T* operator->() { return _ptr; } int UseCount() { return *_pRefCount; } T* Get() { return _ptr; } private: void AddRefCount() { _pMutex->lock(); ++(*_pRefCount); _pMutex->unlock(); }
void Release() { bool deleteflag = false; _pMutex.lock(); if (--(*_pRefCount) == 0) { delete _ptr; delete _pRefCount; deleteflag = true; } _pMutex.unlock(); if (deleteflag == true) delete _pMutex; }
int* _pRefCount; T* _ptr; mutex* _pMutex; };
|
仿函数删除器
上面代码析构函数是用delete来释放资源的,但是我们可能用以下几种方式申请资源:
SharedPtr<int> p(new int);
SharedPtr<FILE> fp(fopen("./test","r"));
SharedPtr<int> mp = ((int*)malloc(sizeof(int)));
这时候使用delete来释放,可能会出错,这时候就需要自定义删除方式,我们只需对上面代码稍加修改即可:
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
| template<class T> class Delete { public: void operator()(T*& p) { if (p != nullptr) { delete p; p = nullptr; } } };
template<class T> class Free { public: void operator()(T*& p) { if (p != nullptr) { free(p); p == nullptr; } } };
class Close { public: void operator()(FILE*& p) { if (p != nullptr) { fclose(p); p = nullptr; } } };
template <class T, class D = Delete<T>> class SharedPtr { public: void Release() { bool deleteflag = false; _pMutex.lock(); if (--(*_pRefCount) == 0) { D()(_ptr); delete _pRefCount; deleteflag = true; } _pMutex.unlock(); if (deleteflag == true) delete _pMutex; } }
|
使用方式:
SharedPtr<int> np(new int);
SharedPtr<FILE, Close<FILE>> fp(fopen("./test","r"));
SharedPtr<int, Free<int>> mp((int*)malloc(sizeof(int)));
shared_ptr的循环引用
shared_ptr并非完美,也有小缺陷
比如:
1 2 3 4 5 6 7 8 9 10 11 12
| struct ListNode { int _data; shared_ptr<ListNode> _prev; shared_ptr<ListNode> _next; ~ListNode() { cout << "~ListNode()" << endl; } }; void test() { shared_ptr<ListNode> node1(new ListNode); shared_ptr<ListNode> node2(new ListNode); node1->_next = node2; node2->_prev = node1; }
|
出作用域后node1和node2对象被释放
但是引用计数不为0,_date不会被释放,造成内存泄漏
当然,C++11库中也给出了响应的解决方法,就是weak_ptr
weak_ptr
weak_ptr要和shared_ptr搭配使用,在进行如上的赋值时,并不进行引用计数的加加操作,这也保证了在释放的时候不会因为引用计数不为0而没有正确释放,造成内存泄漏
1 2 3 4 5 6
| struct ListNode { int _data; weak_ptr<ListNode> _prev; weak_ptr<ListNode> _next; ~ListNode() { cout << "~ListNode()" << endl; } };
|
C++11 守卫锁
lock_guard利用RAII思想,通过对象的生命周期控制锁的生命周期构造加锁,析构解锁,防止死锁
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
| template<class Mutex> class LockGuard { public: LockGuard(Mutex& mtx) :_mutex(mtx) { _mutex.lock(); } ~LockGuard() { _mutex.unlock(); } LockGuard(const LockGuard<Mutex>&) = delete; private: Mutex& _mutex; };
void Fuc() { mutex mtx; { LockGuard<mutex> lg(mtx); } }
|