单例模式应用 | 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的作用非常有限,因为它存在被管理资源的所有权转移 ...
随机推荐
- LeetCode-025-K 个一组翻转链表
K 个一组翻转链表 题目描述:给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表. k 是一个正整数,它的值小于或等于链表的长度. 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保 ...
- css边框普通属性
border :(边框): 其实现在的border是三个属性合成的, border-width:边框大小: border-style:边框的样式: border-color:边框的颜色: 合成以后的用 ...
- echarts可视显示已租未租
1:菜鸟引入js <!-- 引入 echarts.js --> <script src="https://cdn.staticfile.org/echarts/4.3.0/ ...
- tp6 的安装步骤 及简易命令
1:https://www.kancloud.cn/manual/thinkphp6_0/1037481 官网下载 composer create-project topthink/think tp6 ...
- pandas常用操作详解——info()与descirbe()
概述 df.info():主要介绍数据集各列的数据类型,是否为空值,内存占用情况: df.describe(): 主要介绍数据集各列的数据统计情况(最大值.最小值.标准偏差.分位数等等). df.in ...
- CF809E题解
给定一个排列 \(a_i\) 和一棵树,求: \[\frac 1 {n(n-1)}\sum_{i=1}^n\sum_{j=1}^n \varphi(a_i \times a_j) \times dis ...
- 『德不孤』Pytest框架 — 15、Pytest参数化
目录 1.Pytest参数化说明 2.Pytest参数化方式 3.parametrize装饰器参数说明 4.Pytest参数化(单个参数) 5.Pytest参数化(多个参数) 6.ids参数说明 1. ...
- 宏参数(Arguments)的扩展
宏分为两种,一种是 object-like 宏,比如: #define STR "Hello, World!" 另一种是 function-like 宏,比如: #define M ...
- 面向服务开发(SOA)
面向服务的体系结构是一个组件模型,它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来.接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台.操作系统和编程语言 ...
- Windows10 1809版本Windows自动更新服务无法禁用问题解决方案
症状 Windows Update服务已经在服务管理器中禁用,但是莫名奇妙的会被自动设置为手动,并会自动下载补丁.原因 微软加强了系统更新服务的保护措施,导致按照原有的禁用服务方法,能够随时被恢复.解 ...