RAII
利用对象生命周期控制程序资源的简单技术,在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期始终保持有效,在析构时释放资源,就是把管理资源的责任托管给了对象
智能指针的原理
auto_ptr
template < class T>
class Auto_Ptr{
public:
Auto_Ptr(T* ptr = nullptr)
:_ptr(ptr)
{}
~Auto_Ptr(){
if (_ptr)
delete _ptr;
}
//发生拷贝时将ap与资源断开联系,防止一块空间被多个对象使用
//但是拷贝后的ap指针对象赋空,后续访问ap对象会出问题
Auto_Ptr(Auto_Ptr<T>& ap)
:_ptr(ap._ptr)
{
ap._ptr = nullptr;
}
Auto_Ptr<T>& operator= (Auto_Ptr<T>& ap){
if (this != &ap){
if (_ptr)//释放当前对象资源
delete _ptr;
//转移ap的资源
_ptr = ap._ptr;
ap._ptr = nullptr;
}
return *this;
}
T& operator*(){
return *_ptr;
}
T* operator->(){
return _ptr;
}
private:
T* _ptr;
};
unique_ptr
auto_ptr拷贝构造后原对象赋空,所以C++11提供了unique_ptr,实现原理就是防拷贝
template <class T>
class Unique_Ptr{
public:
Unique_Ptr(T* ptr = nullptr)
:_ptr(ptr)
{}
~Unique_Ptr(){
if (_ptr)
delete _ptr;
}
T& operator*(){
return *_ptr;
}
T* operator->(){
return _ptr;
}
private:
Unique_Ptr(Unique_Ptr<T> const&);
Unique_Ptr& operator=(Unique_Ptr<T> const&);
//C++11写法
//Unique_Ptr(Unique_Ptr<T> const&) = delete;
//Unique_Ptr& operator=(Unique_Ptr<T> const&) = delete;
T* _ptr;
};
shared_ptr
- C++11提供了支持拷贝的shared_ptr,实现原理是通过引用计数的方式实现多个shared_ptr对象之间共享资源
- shared_ptr内部维护了一份计数,用来记录该份资源被几个对象共享
- 在对象调用析构函数时,计数减一,当计数为0时,说明自己是最后一个资源,必须释放该资源,如果不是0,说明有其他对象还在使用该资源,不能释放
template <class T>
class Shared_Ptr{
public:
Shared_Ptr(T* ptr = nullptr)
:_ptr(ptr)
, _pRefCount(new int(1))
, _pMutex(new mutex)
{
//如果是空指针对象,引用计数给0
if (_ptr == nullptr)
*_pRefCount = 0;
}
~Shared_Ptr(){
Release();
}
Shared_Ptr(Shared_Ptr<T> const& sp)
:_ptr(sp._ptr)
, _pRefCount(sp._pRefCount)
, _pMutex(sp._pMutex)
{
//拷贝一非空指针对象增加引用计数
if (_ptr)
AddRefCount();
}
Shared_Ptr<T>& operator=(const Shared_Ptr<T>& sp){
if (_ptr != sp._ptr){
Release();
_ptr = sp._ptr;
_pRefCount = sp._pRefCount;
_pMutex = sp._pMutex;
if (_ptr)
AddRefCount();
}
return *this;
}
T& operator*(){
return *_ptr;
}
T* operator->(){
return _ptr;
}
int AddRefCount(){
//引用计数加一的原子操作
_pMutex->lock();
++(*_pRefCount);
_pMutex->unlock();
return *_pRefCount;
}
int SubRefCount(){
//引用计数减一的原子操作
_pMutex->lock();
--(*_pRefCount);
_pMutex->unlock();
return *_pRefCount;
}
private:
void Release(){
if (_ptr&&SubRefCount() == 0){
//引用计数为0时释放资源
delete _ptr;
delete _pRefCount;
}
}
T* _ptr;
int* _pRefCount;//引用计数
mutex* _pMutex;//互斥锁
};
shared_ptr<int> X(new int);//线程间共享的shared_ptr
shared_ptr<int> A; //线程A的局部变量
shared_ptr<int> B(new int);//线程B的局部变量
先执行A = X,指针对象赋值过去,但引用计数还没来得及赋值就切换到了另一个线程
此时int1对象已销毁,x._ptr成了空悬指针,最后回到线程A
struct ListNode{
int _data;
//shared_ptr<ListNode> _prev;
//shared_ptr<ListNode> _next;
weak_ptr<ListNode> _prev;
weak_ptr<ListNode> _next;
~ListNode(){
cout << "~ListNode" << endl;
}
};
- 当node1的_next指向node2,node2的_prev指向node1时
- 当node1和node2析构引用计数减到1,但是_prev和_next还指向节点
- 当_prev和_next析构,node1和node2也就释放了
- 但是node1和node2分别由_prev和_next管理,_prev和_next属于node的成员,谁也不会释放
如果对象时静态建立的,shared_ptr设计了一个仿函数删除器来解决
template <class T>
struct FreeFunc{
void operator()(T* ptr){
free(ptr);
}
};
template <class T>
struct DeleteFunc(){
void operator()(T* ptr){
delete[] ptr;
}
};