在C++中,动态内存的管理是用一对运算符完成的:new和delete,new:在动态内存中为对象分配一块空间并返回一个指向该对象的指针,delete:指向一个动态独享的指针,销毁对象,并释放与之关联的内存。
动态内存管理经常会出现两种问题:一种是忘记释放内存,会造成内存泄漏;一种是尚有指针引用内存的情况下就释放了它,就会产生引用非法内存的指针。
因此为了更加容易和安全的使用动态内存,引入了智能指针的概念
智能指针的行为类似常规指针,重要的区别是他负责自动释放所指向的对象。
智能指针共分为4种,即boost库中的auto_ptr、scoped_ptr、shared_ptr、weak_ptr。
auto_ptr
//正确情况:
int i=new int(1); //堆上的空间——动态开辟
auto_ptr<int> ap1(&i);
//错误情况:
int i=1; //栈上的空间
auot_ptr<int> ap2(&i);
缺陷
- 不要使用auto_ptr保存一个非动态开辟空间的指针,因为在作用域结束的时候,会执行智能指针的析构函数,释放这块空间,但非动态的空间又无法释放;
- 不要使用两个auto_ptr指针指向同一个指针,具体原因上面解释过;
- 不要使用auto_ptr指向一个指针数组,因为auto_ptr的析构函数所用的是delete而不是delete[],不匹配;
- 不要将auto_ptr储存在容器中,因为赋值和拷贝构造后原指针无法使用。
还有最重要的一点就是,什么情况下也别使用auto_ptr智能指针。
scoped_ptr
template<typename T>
class ScopedPtr
{
public:
explicit ScopedPtr(T *p=0):mp(p)
{
}
~ScopedPtr()
{
delete mp;
}
void reset(T *p=0)
{
if(mp!=p)
{
delete mp;
mp=p;
}
}
T &operator*() const
{
if(mp!=0)
return *mp;
else
throw std::runtime_error("the pointer is null");
}
T *operator->() const
{
if(mp!=0)
return mp;
else
throw std::runtime_error("the pointer is null");
}
T *get() const
{
return mp;
}
void swap(ScopedPtr &rhs)
{
T *temp=mp;
mp=rhs.mp;
rhs.mp=temp;
}
private:
ScopedPtr(const ScopedPtr& rhs);
ScopedPtr &operator=(const ScopedPtr& rhs);
T *mp;
};
可以看见最大的不同就是scoped_ptr没有给出拷贝构造和赋值运算符的重载运算符的定义,只给了private下的声明,即表明scoped_ptr智能指针无法使用一个对象创建另一个对象,也无法采用赋值的形式。这无疑提升了智能指针的安全性,但是又存在无法“++”、“–”这些操作,当然也多了“*”、“->”这两种操作。所以这种形式叶并不是最完美的。所以又有了shared_ptr
shared_ptr
template<class T>
class my_shared_ptr{
public:
my_shared_ptr(T* pt){
_pBlock = new ControlBlock(pt);
}
my_shared_ptr(const my_shared_ptr& rhs){
_pBlock = rhs._pBlock;
_pBlock->ref_count++;
}
~my_shared_ptr(){
_pBlock->ref_count --;
if(0 == _pBlock->ref_count)
delete _pBlock;
}
my_shared_ptr& operator=(const my_shared_ptr& rhs){
if(this == &rhs)
return *this;
_pBlock->ref_count --;
if(0 == _pBlock->ref_count)
delete _pBlock;
_pBlock = rhs._pBlock;
_pBlock->ref_count++;
}
T* get(){return _pBlock->_ptr;}
T* operator->(){return _pBlock->_ptr;}
void reset(T* pt){
_pBlock->ref_count --;
if(0 == _pBlock->ref_count)
delete _pBlock;
_pBlock = new ControlBlock(pt);
}
private:
struct ControlBlock{
int ref_count;
T* _ptr;
ControlBlock(T* pt){
_ptr = pt;
ref_count = 1;
}
~ControlBlock(){
delete _ptr;
}
};
ControlBlock* _pBlock;
};
shared_ptr和以上二者的最大区别就是他维护了一个引用计数,用于检测当前对象所管理的指针是否还被其他智能指针使用(必须是shared_ptr管理的智能指针),在析构函数时对其引用计数减一,判断是否为0,若为0,则释放这个指针和这个引用计数的空间。其实,这个原理就和string类的浅拷贝是一样的。
weak_ptr
pragma once #include <memory>
#define _MT_INCR(mtx, x) _InterlockedIncrement(&x)
#define _MT_DECR(mtx, x) _InterlockedDecrement(&x)
#define _MT_CMPX(x, y, z) _InterlockedCompareExchange(&x, y, z)
class RefCountBase
{
private:
virtual void _Destroy() = 0;
virtual void _DeleteThis() = 0;
long _Uses;
long _Weaks;
protected:
RefCountBase()
: _Uses(1)
, _Weaks(1)
{}
public:
virtual ~RefCountBase()
{}
// 如果usecount不为0时,增加usecount的引用计数,成功返回true
bool _Incref_nz()
{
// 循环知道增加成功
for (; ; )
{ // loop until state is known
long _Count = (volatile long&)_Uses;
if (_Count == 0)
return (false);
if (_MT_CMPX(_Uses, _Count + 1, _Count) == _Count)
return (true);
}
}
// 增加usecount
void _Incref()
{
_MT_INCR(_Mtx, _Uses);
}
// 增加weakcount引用计数
void _Incwref()
{
_MT_INCR(_Mtx, _Weaks);
}
// 减少usecount引用计数
void _Decref()
{ // 减少usecount引用计数,如果usecount减后为0,释放资源
if (_MT_DECR(_Mtx, _Uses) == 0)
{
//释放管理的资源,减少weakcount引用计数
_Destroy();
_Decwref();
}
}
// 减少weakcount的引用计数
void _Decwref()
{
if (_MT_DECR(_Mtx, _Weaks) == 0)
_DeleteThis();
}
// 获取usecount
long _Use_count()const
{
return (_Uses);
}
bool _Expired() const
{
return (_Uses == 0);
}
virtual void *_Get_deleter(const _XSTD2 type_info&) const
{
return (0);
}
};
template<class T>
class RefCount: public RefCountBase
{
public:
RefCount(T* p)
: RefCountBase()
, _p(p)
{}
private:
// 释放管理的资源
virtual void _Destroy()
{
delete _p;
}
// 释放自身
virtual void _DeleteThis()
{
delete this;
}
T * _p;
};
template<class T,class Del>
class RefCountDel: public RefCountBase
{
public:
RefCountDel(T *p, Del Dtor)
: RefCountBase()
, _p(p)
, _Dtor(Dtor)
{}
virtual void *_Get_deleter(const _XSTD2 type_info& _Type) const
{ // return address of deleter object
return ((void *)(_Type == typeid(Del) ? &_Dtor : 0));
}
private:
// 释放管理的资源
virtual void _Destroy()
{
_Dtor(_p);
}
virtual void _DeleteThis()
{
delete this;
}
T * _p;
Del _Dtor;
};
//定制空间配置器
template<class T,class Del,class Alloc>
class RefCountDelAlloc: public RefCountBase
{
public:
typedef RefCountDelAlloc<T, Del, Alloc> _Myty;
typedef typename Alloc::template rebind<_Myty>::other _Myalty;
RefCountDelAlloc(T* p, Del Dtor, _Myalty _Al)
: RefCountBase()
, _p(p)
, _Dtor(Dtor)
, _Myal(_Al)
{}
virtual void *_Get_deleter(const _XSTD2 type_info& _Type) const
{
return ((void *)(_Type == typeid(Del) ? &_Dtor : 0));
}
private:
// 释放管理的资源
virtual void _Destroy()
{
_Dtor(_p);
}
// 释放自身
virtual void _DeleteThis()
{ // destroy self
_Myalty _Al = _Myal;
_Dest_val(_Al, this);
_Al.deallocate(this, 1);
}
T * _p;
Del _Dtor; // the stored destructor for the controlled object
_Myalty _Myal; // the stored allocator for this
};
// DECLARATIONS
template<class T>
class WeakPtr;
template<class T>
class SharedPtr;
// SharedPtr和WeakPtr的基类
template<class T>
class PtrBase
{
public:
typedef PtrBase<T> _Myt;
typedef T Elem;
typedef Elem ElementType;
PtrBase()
: _ptr(0)
, _pRef(0)
{}
PtrBase(_Myt&& _Right)
: _ptr(0)
, _pRef(0)
{
_Assign_rv(_STD forward<_Myt>(_Right));
}
// construct _Ptr_base object that takes resource from _Right
_Myt& operator=(_Myt&& _Right)
{
_Assign_rv(_STD forward<_Myt>(_Right));
return (*this);
}
// assign by moving _Right
void _Assign_rv(_Myt&& _Right)
{
if (this != &_Right)
_Swap(_Right);
}
// 获取引用计数
long UseCount() const
{ // return use count
return (_pRef ? _pRef->_Use_count() : 0);
}
void _Swap(PtrBase& _Right)
{
std::swap(_pRef, _Right._pRef);
std::swap(_ptr, _Right._ptr);
}
void* GetDeleter(const _XSTD2 type_info& _Type) const
{
return (_pRef ? _pRef->_Get_deleter(_Type) : 0);
}
T* _Get() const
{
return (_ptr);
}
bool Expired() const
{
return (!_pRef || _pRef->_Expired());
}
// 增加引用计数usecount
void _Decref()
{
if (_pRef != 0)
_pRef->_Decref();
}
void _Reset()
{
_Reset(0, 0);
}
template<class Ty>
void _Reset(const PtrBase<Ty>& pb)
{
_Reset(pb._ptr, pb._pRef);
}
template<class Ty>
void _Reset(Ty *Ptr, const PtrBase<Ty>& pb)
{
_Reset(Ptr, pb._pRef);
}
void _Reset(T* ptr, RefCountBase* pRef)
{
if (pRef)
pRef->_Incref();
_Reset0(ptr, pRef);
}
void _Reset0(T* ptr, RefCountBase *pRef)
{
if (_pRef != 0)
_pRef->_Decref();
_pRef = pRef;
_ptr = ptr;
}
void _Decwref()
{
if (_pRef != 0)
_pRef->_Decwref();
}
void _Resetw()
{
_Resetw((_Elem *)0, 0);
}
template<class Ty>
void _Resetw(const PtrBase<Ty>& pb)
{
_Resetw(pb._ptr, pb._pRef);
}
template<class Ty>
void _Resetw(const Ty* ptr, RefCountBase* pRef)
{
_Resetw(const_cast<Ty*>(ptr), pRef);
}
template<class Ty>
void _Resetw(Ty* ptr, RefCountBase* pRef)
{
if (pRef)
pRef->_Incwref();
if (_pRef != 0)
_pRef->_Decwref();
_pRef = pRef;
_ptr = ptr;
}
private:
T *_ptr;
RefCountBase *_pRef;
};
template<class T>
class SharedPtr: public PtrBase<T>
{
public:
typedef SharedPtr<T> _Myt;
typedef PtrBase<T> _Mybase;
SharedPtr()
{}
explicit SharedPtr(T* p)
{
_Resetp(p);
}
// 带有删除器的构造函数
template<class U,class Del>
SharedPtr(U *p, Del Dt)
{
_Resetp(p, Dt);
}
// 带有空间配置器的构造函数
template<class U,class D,class Alloc>
SharedPtr(U *p, D Dt, Alloc Ax)
{
_Resetp(p, Dt, Ax);
}
SharedPtr(const _Myt& _Other)
{
this->_Reset(_Other);
}
template<class Ty>
explicit SharedPtr(const WeakPtr<Ty>& _Other,bool _Throw = true)
{
this->_Reset(_Other, _Throw);
}
template<class Ty>
explicit SharedPtr(const WeakPtr<Ty>& _Other)
{
this->_Reset(_Other, _Throw);
}
~SharedPtr()
{
this->_Decref();
}
_Myt& operator=(const _Myt& _Right)
{
SharedPtr(_Right).Swap(*this);
return (*this);
}
void Reset()
{
SharedPtr().swap(*this);
}
template<class U>
void Reset(U* p)
{
SharedPtr(p).swap(*this);
}
template<class U,class Del>
void Reset(U* p, Del Dt)
{
SharedPtr(p, Dt).swap(*this);
}
template<class U,class D,class _Alloc>
void Reset(U *P, D Del, _Alloc _Ax)
{
SharedPtr(P, Del, _Ax).swap(*this);
}
void Swap(_Myt& sp)
{
this->_Swap(sp);
}
T* Get() const
{
return (this->_Get());
}
T& operator*() const
{
return (*this->_Get());
}
T* operator->() const
{
return (this->_Get());
}
bool Unique() const
{
return (this->use_count() == 1);
}
private:
template<class U>
void _Resetp(U* p)
{
_Resetp0(p, new RefCount<U>(p));
}
template<class U,class D>
void _Resetp(U *p, D Del)
{
_Resetp0(p, new RefCountDel<U, D>(p, Del));
}
public:
template<class U>
void _Resetp0(U* p, RefCountBase* pRef)
{
this->_Reset0(p, pRef);
}
};
template<class T>
void Swap(SharedPtr<T>& _Left,SharedPtr<T>& _Right)
{
_Left.swap(_Right);
}
template<class D,class T>
D* GetDeleter(const SharedPtr<T>& _Sx)
{
return ((D *)_Sx._Get_deleter(typeid(D)));
}
template<class T>
class WeakPtr: public PtrBase<T>
{
public:
WeakPtr()
{}
WeakPtr(const WeakPtr& wp)
{
this->_Resetw(wp);
}
~WeakPtr()
{
this->_Decwref();
}
WeakPtr& operator=(const WeakPtr& wp)
{
this->_Resetw(wp);
return (*this);
}
WeakPtr& operator=(SharedPtr<T>& sp)
{
this->_Resetw(sp);
return (*this);
}
void Reset()
{
this->_Resetw();
}
void Swap(WeakPtr& _Other)
{
this->_Swap(_Other);
}
bool Expired() const
{
return (this->_Expired());
}
};
weak_ptr也维护了一个引用计数,跟shared_ptr维护的引用计数或互不干扰,或相互协同。weak_ptr的指针会在weak_ptr维护的引用计数上加一,而shared_ptr会在shared_ptr维护的引用计数上加一,这样在循环引用时,就会因为对不同引用的判断的不同,使最终决定是否释放空间的结果也不相同。