带有引用计数的智能指针 shared_ptr 强智能指针
引用计数: 有多少个智能指针对象管理这个堆内存
设计类 : 引用计数管理器 智能指针
图示:
赋值运算符的重载:
sp1=sp2;
1) sp1 sp2管理同一个内存块
delRef(); addRef();
2) sp1 sp2管理不同的内存块
delRef(); addRef();
代码:
#include<iostream>
using namespace std;
class RefManage
{
public:
RefManage():length(0)
{}
void addRef(void* ptr)
{
if (ptr != NULL)
{
int index = Find(ptr);
if (index < 0)//新的节点
{
/*arr[length].addr = ptr;
arr[length++].refcount++;*/
Node tmp(ptr, 1);
arr[length++] = tmp;
}
else
{
arr[index].refcount++;
}
}
}
void delRef(void* ptr)
{
if (ptr != NULL)
{
int index = Find(ptr);
if (index < 0)
{
throw exception("addr is not exist");
}
else
{
if (arr[index].refcount != 0)
{
arr[index].refcount--;
}
}
}
}
int getRef(void* ptr)
{
if (ptr == NULL)
{
return 0;
}
int index = Find(ptr);
if (index < 0)
{
return -1;
}
else
{
return arr[index].refcount;
}
}
private:
int Find(void* ptr)
{
for (int i = 0; i < length; i++)
{
if (arr[i].addr == ptr)
{
return i;
}
}
return -1;
}
class Node
{
public:
Node(void* ptr, int ref = 0)
{
addr = ptr;
refcount = ref;
}
Node()
{
memset(this, 0, sizeof(Node));//清零
}
public:
void* addr;
int refcount;
};
Node arr[5];
int length;//有效节点个数 当前要插入的节点下标
};
template<typename T>
class ShardPtr
{
public:
ShardPtr(T* ptr) :mptr(ptr)
{
AddRef();
}
ShardPtr(const ShardPtr<T>& rhs):mptr(rhs.mptr)
{
AddRef();
}
ShardPtr<T>& operator=(const ShardPtr<T>& rhs)
{
if (this != &rhs)
{
DelRef();
if (GetRef() == 0)
{
delete mptr;
}
mptr = rhs.mptr;
AddRef();//相当于this指针调用
}
return *this;
}
~ShardPtr()
{
DelRef();
if (GetRef() == 0)
{
delete mptr;
}
mptr = NULL;
}
T* operator->()
{
return mptr;
}
T* operator*()
{
return *mptr;
}
private:
void AddRef()
{
rm->addRef(mptr);
}
void DelRef()
{
rm->delRef(mptr);
}
int GetRef()
{
return rm->getRef(mptr);
}
T* mptr;
static RefManage* rm;
};
template<typename T>
RefManage* ShardPtr<T>::rm = new RefManage();
int main()
{
int *p = new int;
ShardPtr<int> sp1(p);
ShardPtr<int> sp2(p);
ShardPtr<int> sp3(p);
return 0;
}
调试代码:
当有多个地方使用引用计数管理器时,将引用计数管理器设为单例模式(线程安全)。
代码:
#include<iostream>
using namespace std;
class RefManage
{
public:
static RefManage* getInstance()//静态函数不依赖于对象的调用,不能设计为普通的成员方法
{
return &rm;
}
private:
RefManage() :length(0)
{}
RefManage(const RefManage& rhs);
public:
void addRef(void* ptr)
{
if (ptr != NULL)
{
int index = Find(ptr);
if (index < 0)//新的节点
{
/*arr[length].addr = ptr;
arr[length++].refcount++;*/
Node tmp(ptr, 1);
arr[length++] = tmp;
}
else
{
arr[index].refcount++;
}
}
}
void delRef(void* ptr)
{
if (ptr != NULL)
{
int index = Find(ptr);
if (index < 0)
{
throw exception("addr is not exist");
}
else
{
if (arr[index].refcount != 0)
{
arr[index].refcount--;
}
}
}
}
int getRef(void* ptr)
{
if (ptr == NULL)
{
return 0;
}
int index = Find(ptr);
if (index < 0)
{
return -1;
}
else
{
return arr[index].refcount;
}
}
private:
int Find(void* ptr)
{
for (int i = 0; i < length; i++)
{
if (arr[i].addr == ptr)
{
return i;
}
}
return -1;
}
class Node
{
public:
Node(void* ptr, int ref = 0)
{
addr = ptr;
refcount = ref;
}
Node()
{
memset(this, 0, sizeof(Node));//清零
}
public:
void* addr;
int refcount;
};
Node arr[5];
int length;//有效节点个数 当前要插入的节点下标
static RefManage rm;
};
RefManage RefManage::rm;//在main函数调用之前就生成 .data
template<typename T>
class ShardPtr
{
public:
ShardPtr(T* ptr) :mptr(ptr)
{
AddRef();
}
ShardPtr(const ShardPtr<T>& rhs):mptr(rhs.mptr)
{
AddRef();
}
ShardPtr<T>& operator=(const ShardPtr<T>& rhs)
{
if (this != &rhs)
{
DelRef();
if (GetRef() == 0)
{
delete mptr;
}
mptr = rhs.mptr;
AddRef();//相当于this指针调用
}
return *this;
}
~ShardPtr()
{
DelRef();
if (GetRef() == 0)
{
delete mptr;
}
mptr = NULL;
}
T* operator->()
{
return mptr;
}
T* operator*()
{
return *mptr;
}
private:
void AddRef()
{
rm->addRef(mptr);
}
void DelRef()
{
rm->delRef(mptr);
}
int GetRef()
{
return rm->getRef(mptr);
}
T* mptr;
static RefManage* rm;
};
template<typename T>
RefManage* ShardPtr<T>::rm = RefManage::getInstance();
int main()
{
int *p = new int;
ShardPtr<int> sp1(p);
ShardPtr<int> sp2(p);
ShardPtr<int> sp3(p);
return 0;
}
强智能指针存在的问题:
如果加上这样的代码:
class B;
class A
{
public:
A()
{
cout << "A()" << endl;
}
~A()
{
cout << "~A()" << endl;
}
ShardPtr<B> pb;
};
class B
{
public:
B()
{
cout << "B()" << endl;
}
~B()
{
cout << "~B()" << endl;
}
ShardPtr<A> pa;
};
int main()
{
ShardPtr<A> spa(new A());
ShardPtr<B> spb(new B());
spa->pb = spb;
spb->pa = spa;
return 0;
}
打印结果:
观察会发现,打印结果只有构造,没有析构,原因是,智能指针的相互引用。
ShardPtr<A> spa(new A());
ShardPtr<B> spb(new B());
spa->pb = spb;
spb->pa = spa;
上面这段代码,做的事情:智能指针的相互引用,一赋值,引用计数就会增加,当引用计数减为1的时候,对象不会销毁,所以出现没有调用构造函数的情况。
如图:
解释:
解决:
先了解一下,强弱智能指针;
强智能指针:share_ptr,引用计数都会加。
弱智能指针: weak_ptr, 只做管理,其他不做。