单例模式应用 | 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的作用非常有限,因为它存在被管理资源的所有权转移 ...
随机推荐
- 《Symfony 5全面开发》教程04、Symfony处理http请求的流程
当我们访问项目的/test路径时,浏览器会向我们的服务器端发送一个请求.我们打开浏览器的开发者工具,打开network选项卡. 在地址栏中敲击回车,浏览器向我们的服务器端发送了一个请求.请求的地址是1 ...
- buu EZ三剑客-EzWeb
查看源码 发现有提示 get 传secret , 尝试随便串值 http://......./?serect=1 发现这是linux命令, net-tools工具中的ifconfig ,但这个工具逐渐 ...
- Tableau绘图一热图、日历图、人口金字塔、标靶图、凹凸图、帕累托图
Tableau绘图一热图.日历图.人口金字塔.标靶图.凹凸图.帕累托图 本文首发于博客冰山一树Sankey,去博客浏览效果更好.直接右上角搜索该标题即可 一.热图 例子:示例超市 可以通过更改颜色来改 ...
- MIPI CSI-2 像素打包格式解析
背景 MIPI CSI-2支持YUV.RGB和RAW data三种数据格式,这里是个笼统的叫法,具体又根据不同的像素打包方式细分为具体的格式,打包是什么概念?就是把Sensor采样得到的RGB三个通道 ...
- nginx lua模块常用的指令
lua_code_cache 语法:lua_code_cache on | off 默认: on 适用上下文:http.server.location.location if 这个指令是指定是否开启l ...
- 手写 Vue2 系列 之 patch —— diff
前言 上一篇文章 手写 Vue2 系列 之 初始渲染 中完成了原始标签.自定义组件.插槽的的初始渲染,当然其中也涉及到 v-bind.v-model.v-on 指令的原理.完成首次渲染之后,接下来就该 ...
- 2.3 C++STL vector容器详解
文章目录 2.3.1 引入 2.3.2 代码实例 2.3.3 运行结果 总结 2.3.1 引入 vector 容器 动态数组 可变数组 vector容器 单口容器(尾部操作效率高) vector动态增 ...
- 在命令行运行 python 抛出 ModuleNotFoundError 的解决方法
所要运行的 py 文件在子目录中,并且该文件引用了另一个子目录中的 py 模块.类似这样: 原因 在运行环境下, a.py 找不到 b.py 所以抛出 ModuleNotFoundError. 解决 ...
- 初探 Elasticsearch,学习笔记第一讲
1. ES 基础 1.1 ES定义 ES=elaticsearch简写, Elasticsearch是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储.检索数据:本身扩展 ...
- python+pytest接口自动化(10)-session会话保持
在接口测试的过程中,经常会遇到有些接口需要在登录的状态下才能请求,否则会提示请登录,那么怎样解决呢? 上一篇文章我们介绍了Cookie绕过登录,其实这就是保持登录状态的方法之一. 另外一种方式则是通过 ...