在我们模拟设计 shared_ptr 智能指针时发现,不同类型的 Shared_ptr 不能使用同一个引用计数管理器,这显然会造成内存上的浪费。因此我们考虑将其设计为单例模式使其所有的 Shared_ptr指针 共享一个引用管理计数器 rm。具体实现如下:
ps:在Node arr[10];
语句 设计引用计数管理器的容量时可以考虑采用自动增长类型,如 STL 中的 vector 。
/* 引用计数管理类 */
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++;
length++;
}
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()
{
memset(this, 0, sizeof(Node));
}
public:
void* addr; /* 保存堆内存地址 */
int refCount; /* 保存该堆内存引用次数 */
};
Node arr[10]; /* 用数组模拟10个空间的引用计数器*/
int length; /* 有效结点个数、当前要插入的下标*/
static RefManage rm;
};
RefManage RefManage::rm;
template<typename T>
class Shared_ptr
{
public:
Shared_ptr(T* ptr = NULL) :m_ptr(ptr)
{
AddRef();
}
Shared_ptr(const Shared_ptr<T>& rhs)
:m_ptr(rhs.m_ptr)
{
AddRef();
}
Shared_ptr<T>& operator=(const Shared_ptr<T>& rhs)
{
if (this != &rhs)
{
/* 自身引用次数减一 */
DelRef();
/* 若引用次数为0,则立刻释放 */
if (GetRef() == 0)
{
delete m_ptr;
}
m_ptr = rhs.m_ptr;
AddRef();
}
return *this;
}
~Shared_ptr()
{
DelRef();
if (GetRef() == 0)
{
delete m_ptr;
}
m_ptr = NULL;
}
T& operator*() const
{
return *m_ptr;
}
T* operator->() const
{
return m_ptr;
}
private:
void AddRef()
{
rm->addRef(m_ptr);
}
void DelRef()
{
rm->delRef(m_ptr);
}
int GetRef()
{
return rm->getRef(m_ptr);
}
T* m_ptr;
static RefManage* rm;
};
/* 静态成员变量在类外初始化 */
template<typename T>
RefManage* Shared_ptr<T>::rm = RefManage::getInstance();
在main 中进行测试
int main()
{
int* p = new int;
Shared_ptr<int> sp1(p);
Shared_ptr<int> sp2(p);
Shared_ptr<int> sp3(new int());
Shared_ptr<int> sp4(new int());
Shared_ptr<int> sp5(new int);
Shared_ptr<int> sp6(sp5);
/* char 类型 以及 double 类型 */
Shared_ptr<char> csp1(new char);
Shared_ptr<char> csp2(csp1);
Shared_ptr<double> dsp1(new double);
Shared_ptr<double> dsp2(new double);
return 0;
}
运行测试,我们可以看到三个 Shared_ptr 的地址实际上都是同一地址,也就是说,在不同类型的智能指针中都使用了同一个引用计数管理器。
附:
单例模式:添加链接描述https://blog.csdn.net/weixin_43919932/article/details/103016971