单例模式应用 | Shared_ptr引用计数管理器
在我们模拟设计 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
单例模式应用 | Shared_ptr引用计数管理器的更多相关文章
- shared_ptr 引用计数
https://zh.cppreference.com/w/cpp/memory/shared_ptr 引用计数
- iOS中引用计数内存管理机制分析
在 iOS 中引用计数是内存的管理方式,虽然在 iOS5 版本中,已经支持了自动引用计数管理模式,但理解它的运行方式有助于我们了解程序的运行原理,有助于 debug 程序. 操作系统的内存管理分成堆和 ...
- 内存管理 垃圾回收 C语言内存分配 垃圾回收3大算法 引用计数3个缺点
小结: 1.垃圾回收的本质:找到并回收不再被使用的内存空间: 2.标记清除方式和复制收集方式的对比: 3.复制收集方式的局部性优点: https://en.wikipedia.org/wiki/C_( ...
- iOS开发--引用计数与ARC
以下是关于内存管理的学习笔记:引用计数与ARC. iOS5以前自动引用计数(ARC)是在MacOS X 10.7与iOS 5中引入一项新技术,用于代替之前的手工引用计数MRC(Manual Refer ...
- cocos2d-x 从onEnter、onExit、 引用计数 谈内存泄露问题
/////////////////////////////////// //author : zhxfl //date : 2013.8.29 //email : 291221622@qq.co ...
- juce中的引用计数
这个类提供了最基本的引用计数管理,界面库中,经常都需要消息发送,而带来的后果就是不知道消息中包含的对象是否还存在,如果不能很好管理的话就容易出现访问销毁了的对象这样的情况,所以,juce的界面无素也基 ...
- cocos2D-x 3.5 引擎解析之--引用计数(Ref),自己主动释放池(PoolManager),自己主动释放池管理器( AutoreleasePool)
#include <CCRef.h> Ref is used for reference count manangement. If a classinherits from Ref. C ...
- Objective-C内存管理之-引用计数
本文会继续深入学习OC内存管理,内容主要参考iOS高级编程,Objective-C基础教程,疯狂iOS讲义,是我学习内存管理的笔记 内存管理 1 内存管理的基本概念 1.1 Objective-C中的 ...
- std::shared_ptr 和 std::weak_ptr的用法以及引用计数的循环引用问题
在std::shared_ptr被引入之前,C++标准库中实现的用于管理资源的智能指针只有std::auto_ptr一个而已.std::auto_ptr的作用非常有限,因为它存在被管理资源的所有权转移 ...
随机推荐
- Linux图形界面和命令界面切换
转至:https://blog.csdn.net/weixin_43683466/article/details/85727723 1.若虚拟机内热键被占用,可通过下图所示修改,移出快捷键ctrl+a ...
- 反压缩 js ,我的万花筒写轮眼开了,CV 能力大幅提升
前言 因为比较菜,所以经常需要读一些别人的代码学习学习. 有源码的代码当然好,但是很多网站不开源.这些网站的 js 又都是打包压缩过的,学习起来很难受. 所以我做了一个小工具,通过修改抽象语法树,来处 ...
- PHP日常错误总结
session问题 问题描述 初到公司开发的项目在本地测试没有问题,部署到线上之后出来验证码一直错误,或者是CSRF token mismatch. 这些问题都是和session有关系,打开两个页面, ...
- cookie、session和Storage
概念: cookie:HTTP响应头的一部分,通过name=value的形式存储,主要用于保存登录信息.在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭. 存放数据大小为4K左右 .有个 ...
- interrupt(),interrupted() 和 isInterrupted() 的区别
1. 结论先行 interrupt():将调用该方法的对象所表示的线程标记一个停止标记,并不是真的停止该线程. interrupted():获取当前线程的中断状态,并且会清除线程的状态标记.是一个是静 ...
- SpringBoot中常用的45个注解
1.SpringBoot/spring @SpringBootApplication: 包含@Configuration.@EnableAutoConfiguration.@ComponentScan ...
- JAVA 线上问题排查方法
CPU 磁盘 内存 GC问题 网络 线上故障主要会包括cpu.磁盘.内存以及网络问题,而大多数故障可能会包含不止一个层面的问题,所以进行排查时候尽量四个方面依次排查一遍. 同时例如jstack.jma ...
- K8S搭建自动化部署环境 Jenkins下载、安装和启动
镜像下载.域名解析.时间同步请点击 阿里云开源镜像站 一.jenkins 下载 jenkins下载地址:https://jenkins.io/zh/download/ 如下图,左边是稳定版本,右边是每 ...
- Linux系统配置(系统优化)
镜像下载.域名解析.时间同步请点击 阿里云开源镜像站 前言 系统安装完成后,需要基于系统做出一些调整来让系统使用起来更加顺手,可以根据个人喜好对linux进行调整,还有一些是linux的必要设置 一 ...
- kubernetes资源使用glusterfs卷进行数据持久化
1.GlusterFS部署 安装GlusterFS集群的主要目的是为k8s集群提供分布式持久化存储. GlusterFS部署使用2台服务器,服务名称与IP如下: 1 db-storagea 10.1. ...