在我们模拟设计 shared_ptr 智能指针时发现,不同类型的 Shared_ptr 不能使用同一个引用计数管理器,这显然会造成内存上的浪费。因此我们考虑将其设计为单例模式使其所有的 Shared_ptr指针 共享一个引用管理计数器 rm。具体实现如下:

ps:在Node arr[10];语句 设计引用计数管理器的容量时可以考虑采用自动增长类型,如 STL 中的 vector 。

  1. /* 引用计数管理类 */
  2. class RefManage
  3. {
  4. public:
  5. static RefManage* getInstance()
  6. {
  7. return &rm;
  8. }
  9. private:
  10. RefManage() : length(0) {}
  11. RefManage(const RefManage& rhs);
  12. public:
  13. /* 增加引用计数 */
  14. void addRef(void* ptr)
  15. {
  16. if (ptr != NULL)
  17. {
  18. int index = Find(ptr);
  19. if (index < 0)
  20. {
  21. arr[length].addr = ptr;
  22. arr[length].refCount++;
  23. length++;
  24. }
  25. else
  26. {
  27. arr[index].refCount++;
  28. }
  29. }
  30. }
  31. /* 删除一个引用计数 */
  32. void delRef(void* ptr)
  33. {
  34. if (ptr != NULL)
  35. {
  36. int index = Find(ptr);
  37. if (index < 0)
  38. {
  39. throw exception("addr is not exist");
  40. }
  41. else
  42. {
  43. if (arr[index].refCount != 0)
  44. {
  45. arr[index].refCount--;
  46. }
  47. }
  48. }
  49. }
  50. /* 返回当前堆内存的引用计数 */
  51. int getRef(void* ptr)
  52. {
  53. if (ptr == NULL)
  54. {
  55. return 0;
  56. }
  57. int index = Find(ptr);
  58. if (index < 0)
  59. {
  60. return -1;
  61. }
  62. else
  63. {
  64. return arr[index].refCount;
  65. }
  66. }
  67. private:
  68. /* 查找是否是已经存在的堆区空间 */
  69. int Find(void* ptr)
  70. {
  71. for (int i = 0; i < length; ++i)
  72. {
  73. if (arr[i].addr == ptr)
  74. {
  75. return i;
  76. }
  77. }
  78. return -1;
  79. }
  80. /* 局部类,储存引用计数信息 */
  81. class Node
  82. {
  83. public:
  84. Node()
  85. {
  86. memset(this, 0, sizeof(Node));
  87. }
  88. public:
  89. void* addr; /* 保存堆内存地址 */
  90. int refCount; /* 保存该堆内存引用次数 */
  91. };
  92. Node arr[10]; /* 用数组模拟10个空间的引用计数器*/
  93. int length; /* 有效结点个数、当前要插入的下标*/
  94. static RefManage rm;
  95. };
  96. RefManage RefManage::rm;
  97. template<typename T>
  98. class Shared_ptr
  99. {
  100. public:
  101. Shared_ptr(T* ptr = NULL) :m_ptr(ptr)
  102. {
  103. AddRef();
  104. }
  105. Shared_ptr(const Shared_ptr<T>& rhs)
  106. :m_ptr(rhs.m_ptr)
  107. {
  108. AddRef();
  109. }
  110. Shared_ptr<T>& operator=(const Shared_ptr<T>& rhs)
  111. {
  112. if (this != &rhs)
  113. {
  114. /* 自身引用次数减一 */
  115. DelRef();
  116. /* 若引用次数为0,则立刻释放 */
  117. if (GetRef() == 0)
  118. {
  119. delete m_ptr;
  120. }
  121. m_ptr = rhs.m_ptr;
  122. AddRef();
  123. }
  124. return *this;
  125. }
  126. ~Shared_ptr()
  127. {
  128. DelRef();
  129. if (GetRef() == 0)
  130. {
  131. delete m_ptr;
  132. }
  133. m_ptr = NULL;
  134. }
  135. T& operator*() const
  136. {
  137. return *m_ptr;
  138. }
  139. T* operator->() const
  140. {
  141. return m_ptr;
  142. }
  143. private:
  144. void AddRef()
  145. {
  146. rm->addRef(m_ptr);
  147. }
  148. void DelRef()
  149. {
  150. rm->delRef(m_ptr);
  151. }
  152. int GetRef()
  153. {
  154. return rm->getRef(m_ptr);
  155. }
  156. T* m_ptr;
  157. static RefManage* rm;
  158. };
  159. /* 静态成员变量在类外初始化 */
  160. template<typename T>
  161. RefManage* Shared_ptr<T>::rm = RefManage::getInstance();
在main 中进行测试
  1. int main()
  2. {
  3. int* p = new int;
  4. Shared_ptr<int> sp1(p);
  5. Shared_ptr<int> sp2(p);
  6. Shared_ptr<int> sp3(new int());
  7. Shared_ptr<int> sp4(new int());
  8. Shared_ptr<int> sp5(new int);
  9. Shared_ptr<int> sp6(sp5);
  10. /* char 类型 以及 double 类型 */
  11. Shared_ptr<char> csp1(new char);
  12. Shared_ptr<char> csp2(csp1);
  13. Shared_ptr<double> dsp1(new double);
  14. Shared_ptr<double> dsp2(new double);
  15. return 0;
  16. }

运行测试,我们可以看到三个 Shared_ptr 的地址实际上都是同一地址,也就是说,在不同类型的智能指针中都使用了同一个引用计数管理器。


附:

单例模式:添加链接描述https://blog.csdn.net/weixin_43919932/article/details/103016971

单例模式应用 | Shared_ptr引用计数管理器的更多相关文章

  1. shared_ptr 引用计数

    https://zh.cppreference.com/w/cpp/memory/shared_ptr 引用计数

  2. iOS中引用计数内存管理机制分析

    在 iOS 中引用计数是内存的管理方式,虽然在 iOS5 版本中,已经支持了自动引用计数管理模式,但理解它的运行方式有助于我们了解程序的运行原理,有助于 debug 程序. 操作系统的内存管理分成堆和 ...

  3. 内存管理 垃圾回收 C语言内存分配 垃圾回收3大算法 引用计数3个缺点

    小结: 1.垃圾回收的本质:找到并回收不再被使用的内存空间: 2.标记清除方式和复制收集方式的对比: 3.复制收集方式的局部性优点: https://en.wikipedia.org/wiki/C_( ...

  4. iOS开发--引用计数与ARC

    以下是关于内存管理的学习笔记:引用计数与ARC. iOS5以前自动引用计数(ARC)是在MacOS X 10.7与iOS 5中引入一项新技术,用于代替之前的手工引用计数MRC(Manual Refer ...

  5. cocos2d-x 从onEnter、onExit、 引用计数 谈内存泄露问题

    /////////////////////////////////// //author : zhxfl //date   : 2013.8.29 //email  : 291221622@qq.co ...

  6. juce中的引用计数

    这个类提供了最基本的引用计数管理,界面库中,经常都需要消息发送,而带来的后果就是不知道消息中包含的对象是否还存在,如果不能很好管理的话就容易出现访问销毁了的对象这样的情况,所以,juce的界面无素也基 ...

  7. cocos2D-x 3.5 引擎解析之--引用计数(Ref),自己主动释放池(PoolManager),自己主动释放池管理器( AutoreleasePool)

    #include <CCRef.h> Ref is used for reference count manangement. If a classinherits from Ref. C ...

  8. Objective-C内存管理之-引用计数

    本文会继续深入学习OC内存管理,内容主要参考iOS高级编程,Objective-C基础教程,疯狂iOS讲义,是我学习内存管理的笔记 内存管理 1 内存管理的基本概念 1.1 Objective-C中的 ...

  9. std::shared_ptr 和 std::weak_ptr的用法以及引用计数的循环引用问题

    在std::shared_ptr被引入之前,C++标准库中实现的用于管理资源的智能指针只有std::auto_ptr一个而已.std::auto_ptr的作用非常有限,因为它存在被管理资源的所有权转移 ...

随机推荐

  1. 使用linux 的shell脚本进行sftp文件上传与下载

    一.批量上传: #!/bin/bash #SFTP配置信息 #用户名 USER=root #密码 PASSWORD=5EYS40T04BMF #待上传文件根目录 SRCDIR=/u02/dab/sft ...

  2. Mysql基础学习第二天

    Mysql基础学习第二天 函数 函数:是指一段可以直接被另一段程序调用的程序或代码. 字符串函数 数值函数 日期函数 流程函数 字符串函数 MySQL内置很多字符串函数,常用的几个如下: 函数 功能 ...

  3. curl 命令常用

    参考: https://www.cnblogs.com/name-lizonglin/p/12167808.html -- 测试 请求返回时间  测试Pod 之间解析时间   用key为空字符串查me ...

  4. qt日常积累

    http://blog.sina.com.cn/s/blog_b8bcba160102yyi3.html

  5. LeetCode-268-丢失的数字

    丢失的数字 题目描述:给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数. 进阶: 你能否实现线性时间复杂度.仅使用额外常数空间的算法解 ...

  6. quartz框架(七)-JobStore

    JobStore 在之前的博文中,博主已经写了关于Job的相关内容.本篇博文,博主将介绍JobStore相关的内容. JobStore是存放Job和Trigger的地方.当我们调用Scheduler对 ...

  7. vue 组件间的几种通信方式

    Props配置 原理:通过props配置,进行父子组件间的通信,跨父子通信需要其他组件进行过渡. 使用: 传递方在标签中添加传递内容 <Son :newName="name" ...

  8. NTFS权限概述

    NTFS权限概述 NTFS是我常见的一种磁盘格式,在Windows系统中使用广泛,它打破了FAT的局限性.在我使用ntfs格式分区的时候经常会涉及到ntfs权限设置问题,来帮助我们对文件的处理.那么什 ...

  9. numpy: np.logical_and/or/not (逻辑与/或/非)+python3-曲线拟合(polyfit/polyval)

    可以用拟合两个变量之间的关系,然后根据一个变量,去推测出另外一个变量的推测值

  10. python 关于heapq模块的随笔

    heapq模块提供了很多高级功能可以通过help(heapq)查看详细文档: 要点: 1优先级队列让我们可以按照重要程度来处理元素,而不是先进先出 2使用heapq可以应对长列表,因为heap不是复杂 ...