C++98引入了auto_ptr
auto_ptr:
**特点:**管理权限唯一,控制权限唯一<所有权唯一>
只有一个指针对象进行管理,剩下的都会失效.数据无法共享
不能在容器中保存auto_ptr,也不能从函数中返回auto_ptr.
上图所示是错误的,因为所有权是唯一的.
所以在C++11摒弃了auot_ptr:要避免因为潜在的内存问题导致程序崩溃.
auto_ptr的简单实现:
template<typename T>
class Auto_Ptr
{
public:
Auto_Ptr(T* ptr)//构造函数
:mptr(ptr)//初始化
{}
Auto_Ptr(Auto_Ptr<T>& rhs)//拷贝构造函数
{
mptr = rhs.Release();
}
Auto_Ptr<T>& operator=(Auto_Ptr<T>& rhs)//赋值运算符重载
//如果形参和this指针指向同一块内存,系统就会崩溃
{
if (this != &rhs)
{
delete mptr;
mptr = rhs.Release();
}
return *this;
}
~Auto_Ptr()
{
delete mptr;
mptr = NULL;
}
T& operator*()
{
return *mptr;
}
T* operator->()
{
return mptr;
}
private:
T* Release()
{
T* ptmp = mptr;
mptr = NULL;
return ptmp;
}
T* mptr;
};
C++11智能指针:
unique_ptr:
**特点:**1.所有权唯一
2.不支持普通的拷贝或赋值操作.
**shared_ptr:
特点:**1.所有权不唯一,允许多个智能指针指向同一个对象
2.引用计数减为0 释放内存
存在问题:相互引用的问题
std::shared_ptr<A> pa(new A());
std::shared_ptr<B> pb(new B());
pa->spa = pb;
pb->spb = pa;
上面的代码有相互引用的问题,如果说两个shared_ptr相互引用,那么这两个指针的引用计数永远不可能下降为0,资源永远不会释放.
shared_ptr的实现:
class Ref_Mem//引用计数管理器
{
public:
static Ref_Mem* getInstance()
{
return &rm;
}
int getRef(void* ptr)//获得引用计数器
{
if (ptr == NULL)
{
return -1;
//throw std::exception("pointer is NULL");
}
for (int i = 0; i < cursize; i++)
{
if (ptr == ref_count[i].addr)
{
return ref_count[i].count;
}
}
return -1;
}
void addRef(void* ptr)//添加引用计数
{
if (ptr == NULL)
return;
int index = find(ptr);
if (index != -1)
{
ref_count[index].count++;
}
else
{
ref_count[cursize].addr = ptr;
ref_count[cursize++].count = 1;
}
}
void delRef(void* ptr)//减少引用计数
{
if (ptr == NULL)
return;
int index = find(ptr);
if (index == -1)
{
throw std::exception("pointer is error!");
}
if (getRef(ptr) != 0)
{
ref_count[index].count--;
}
}
private:
Ref_Mem()
{
cursize = 0;
}
int find(void* ptr)
{
for (int i = 0; i < cursize; i++)
{
if (ptr == ref_count[i].addr)
{
return i;
}
}
return -1;
}
typedef struct Ref
{
void* addr;
int count;
}Ref;
Ref ref_count[10];
int cursize;
static Ref_Mem rm;
};
Ref_Mem Ref_Mem::rm;
template<typename T>
class Shared_Ptr
{
public:
Shared_Ptr(T* ptr = NULL)
{
mptr = ptr;
prm->addRef(mptr);
}
Shared_Ptr(Shared_Ptr<T>& _Right)
{
mptr = _Right.mptr;
prm->addRef(mptr);
}
Shared_Ptr<T>& operator=(Shared_Ptr<T>& _Right)
{
if (this != &_Right)
{
prm->delRef(mptr);
if (prm->getRef(mptr) == 0)
{
delete mptr;
}
mptr = _Right.mptr;
prm->addRef(mptr);
}
return *this;
}
~Shared_Ptr()
{
prm->delRef(mptr);
if (prm->getRef(mptr) == 0)
{
delete mptr;
}
mptr = NULL;
}
T& operator*()
{
return *mptr;
}
T* operator->()
{
return mptr;
}
private:
T* mptr;
static Ref_Mem* prm;
};
template<typename T>
Ref_Mem* Shared_Ptr<T>::prm = Ref_Mem::getInstance();
为了解决shared_ptr相互引用的问题,引入了weak_ptr
特点:
1.不加引用计数
2.没有释放权限(不能单独使用)
3.shared_ptr和weak_ptr一般结合着来使用
它是对对象的一种弱引用,不会增加对象的引用计数,和shared_ptr之间可以相互转化,shared_ptr可以直接赋值给它,它可以通过调用lock函数来获得shared_ptr。
std::shared_ptr<A> pa(new A());
std::weak_ptr<B> pb(new B());
pa->spa = pb;
pb->spb = pa;
上述代码解决了相互引用带来的死锁问题.