【转载】C++应用引用计数技术

原帖:http://www.cnblogs.com/chain2012/archive/2010/11/12/1875578.html

因为Windows的内核对象也运用了引用计数,所以稍作了解并非无用。

引用计数可以让多个对象共享一个数据,而且免除了跟踪控制权的负担,让对象自己管理自己,当再没有被使用时可以自动删除,也算是一种简易的垃圾回收机制。

另一方面,如果有N多个相同的对象:○=○=○=○=...=○=○ 这样的做法是臃肿且无聊的,所以一个好的做法就是让对象可以共享这一个数据。既可以节省内存,又可以提高效率让程序负担更少,不用构造和析构这个值对象的拷贝了。

1 String a, b, c, d, e;
2 a=b=c=d=e="hello";
复制代码
1 String& String::operator=(const String &rhs)
2 {
3 if (data==&rhs) return *this; //防止自我赋值
4   delete [] data;
5 data = new char[strlen(rhs.data)+1)];
6 strcpy(data, rhs.data);
7 return *this;
8 }
复制代码

用图显示的话,即:

当a被赋予了另外的值,a="world"; 这时候不能删除这个Hello,应外仍然存在bcde,4个对象在共享这个数据;另外,当只有1个对象x在用这个Hello,而x已经超过了其生存期,没有其他对象指向这个Hello的时候,我们需要删除这个Hello确保不发生资源泄漏。这也就意味着引入引用计数后,图将改变成这样:

 

  • 实现引用计数

应该是每一个String值对应一个计数数值,而不是String对象对应一个引用计数。接下来,新建一个嵌套类StringValue来保存计数和其跟踪的值。

复制代码
String.h
 1 #include <string>
2
3  class String {
4  public:
5 String(const char *initValue="");
6 String& String::operator=(const String &rhs);
7
8  private:
9 // StringValue的主要目的是提供一个空间将一个特别的值和共
10 // 享此值的对象的数目联系起来
11 struct StringValue //嵌套类,引用计数
12 {
13 int refCount; //计数数值
14 char *data;
15 StringValue (const char* initValue);
16 ~StringValue();
17 };
18 StringValue *value;
19 };
复制代码
复制代码
String.cpp
 1 #include "String.h"
2
3 String::StringValue::StringValue(const char* initValue)
4 :refCount(1)
5 {
6 data = new char[strlen(initValue)+1];
7 strcpy(data, initValue);
8 }
9
10 String::StringValue::~StringValue()
11 {
12 delete [] data;
13 }
14
15 String::String(const char *initValue)
16 :value(new StringValue(initValue))
17 {
18
19 }
复制代码

而这样做通常会产生一个问题,

String s1("More Effective C++");

String s2("More Effective C++");

将会变成这样的数据结构:

想办法改进一下:

复制代码
控制副本的简单实现
 1 list<string> String::StringValue::independObj; //独立对象
2  String::StringValue::StringValue(const char* initValue)
3 :refCount(1)
4 {
5 typedef list<string>::iterator lsp;
6 lsp p = find(independObj.begin(), independObj.end(), string(initValue));
7 if (p==independObj.end()||independObj.empty())
8 {//未找到对象,新建
9   data = new char[strlen(initValue)+1];
10 strcpy(data, initValue);
11 independObj.push_back(string(data));
12 }
13 else
14 {
15 // do something...
16   }
17 }
复制代码

接下来看下String类的拷贝构造函数

String::String(const String& rhs) 
: value(rhs.value)
{
++value->refCount;
}

当这样构造2个对象:

String s1("More Effective C++");

String s2(s1);

就会产生这样的数据结构,其代价是非常低廉的,省去了新对象的构造(不必分配新内存和把内容拷贝到这块内存中)和之后的析构(不必释放那块内存),仅仅是使计数+1和拷贝了下指针

拷贝构造函数之后看下析构函数

复制代码
String::~String()
{
if (--value->refCount == 0)
{
delete value;
}
}
复制代码

即,当被引用的对象还有其他共享对象时,仅把计数-1;而当没有其他共享对象时,才彻底将引用对象析构掉。接着,是重载赋值操作符,稍微有些复杂

复制代码
String& String::operator=(const String &rhs)
{
if (value == rhs.value) //赋值的是其本身
return *this; //什么也不做
if (--value->refCount == 0) //如果只有当前对象在共享那个数据
delete value; //则删除掉,因为即将被赋予新的引用。不是的话,仅将计数-1
value = rhs.value; //赋值操作
++value->refCount; //计数器+1
return *this;
}
复制代码
  • 写时拷贝

const版本的下标操作仅仅是只读的,不会对引用对象做出修改

const char& String::operator[](int index) const  //const版本
{
//需下标溢出检查
return value->data[index];
}

需要考虑的是非const版本的下标操作,因为C++编译器无法告诉我们非const的operator[]是会被用来读还是写操作。所以我们保守地认为所有的操作都是“写”的。

复制代码
char& String::operator[](int index)  //非const版本
{
if (value.refCount>1) //如果引用对象不止一个
{
--value.refCount; //计数减一,相当于把这个引用删除了
value = new StringValue(value->data); //重新申请一份新的拷贝
}
return value->data[index];
}
复制代码

这个思想就是:“与其他对象共享的一个值直到写操作时才拥有自己的拷贝”。即,lazy原则的特例。

  • 指针、引用与写时拷贝

在大部分情况下都能满足以上的应用,可是唯一情况却颇为棘手,比如

String s1("More Effective C++");

char* p=&s1;

String s2 = s1;

拷贝构造函数让s2和s1共享这个对象,这时候的数据结构为

如果写下这样一句: p[1]='X'; //将同时修改s1和s2的内容!String 的拷贝构造函数无法检测出s1拥有指向StringValue指针的存在。该问题的一个解决方法就是:在每个StringValue中增加一个标志,表示该对象是否可以被共享。在最初是ture状态,而在调用了非const的operator[]之后则设置成false,且之后永远置于false状态。

追加共享标志位的String
  • 带引用计数的基类

引用计数不仅运用在字符串类上,只要是多个对象共享相同值的类都可以。

构建一个基类(RCObject),任何需要引用计数的类都必须继承自此类。由RCObject类封装引用计数功能。

 

RCObject.h
RCObject.cpp
  • 自动引用计数处理

 

RCObject类给了我们一个存储引用计数的地方,并提供了成员函数供我们操作引用计数,但调用这些函数的动作还必须被手工加入其它类中。仍然需要在String的拷贝构造函数和赋值运算函数中调用StringValue的addReference和 removeReference函数。这很笨拙。

StringValue *value; 必须操作StringValue对象的refCount字段。是否能够让指针自身检测发生复制拷贝,赋值操作,析构操作此类事件,而对于计数经行修改的操作呢?答案是否定的。代替的方法就是利用智能指针。

【分析】

开始看函数式treap的时候看到的...

话说函数式treap消耗的内存那么大吗?还要用引用计数。

表示只用内存池。

 顺便附上一份网上函数式treap模板...

http://ideone.com/kbSjPp

转载于:https://www.cnblogs.com/hoskey/p/4329332.html

保姆级教程:手把手带你玩转英飞凌TC397开发板的板载资源(CAN FD、LCD、SD卡) 本文提供英飞凌TC397开发板的全面开发指南,涵盖CAN FD通信、LCD显示、SD卡文件系统和以太网通信等核心功能。通过详细的代码示例和硬件连接说明,帮助开发者快速上手并充分利用开发板的丰富资源,实现高效嵌入式系统开发。 阅读详情

相关推荐

100kHz手持LCR表设计:高频阻抗测量与校准实战解析

阻抗测量是电子元件测试的基础,LCR表通过施加正弦激励并分析电压电流的幅值与相位,即可获取电容、电感、电阻的等效参数。在开关电源、无线充电等高频应用场景中,元件在100kHz下的ESR和阻抗特性尤为关键,传统10kHz手持仪表难以满足需求。本文从自动平衡桥原理出发,探讨如何将台式电桥的核心能力浓缩至手持设备,重点剖析高频寄生参数抑制、模拟链路设计、数字相敏检波算法及开路短路校准方法。通过实测数据验证,在100kHz频率下基本精度可达0.5%以内,为维修现场、产线抽检及硬件调试提供了可携带的精密测量方案。全文

weixin_33910191的博客 398

Windows核心技术--com组件实用入门教程

1.com 组件对象模型 com是微软组件对象模型的简称。由于com具有二进制代码共享的 特性,所以它具备了高可开发性,高度可维护性和高度的可移植性(跨开发语言),以至于在windows上面的诸多应用软件采用了com来做整体的架构。比如微软的DirectX等。com虽然流行于2000-2004年之间,由于它的普及面之广,应用软件种类之繁多再加上windows对其默认支持很好,开发出来的软件无需依赖其他的开发包,所以被很多软件公司采用至今,作为一个VC++程序员,是否系统掌握com的用法称为是否合格的重要的衡

qq_44623314的博客 4898

Deepseek 10分钟化身理性荐股神器:触碰程序员不敢想的天花板

在这个消息疯狂、波动频繁的市场,“理性”两字显得弥足珍贵。通过Deepseek+AkShare+Aktools+Dify四位一体的方案,能帮我们降低信息搜集成本,并在短期投资领域搭建出一套“可解释、低门槛、易定制”的量化荐股流程。不要再盲目听小道消息或依赖情绪驱动,不妨给自己一个机会,让数据说话。而要注意的是,“理性荐股”并非万能,它只是工具,最终的收益还得依赖投资者自身对风险和机遇的权衡。祝大家都能在这股市里收获理性的底气,寻得更精准的入场时机。

qqxdh的博客 3754

C++ 引用计数技术简介(1)

1.引用计数的作用C++引用计数是C++为弥补没有垃圾回收机制而提出的内存管理的一个方法和技巧,它允许多个拥有共同值的对象共享同一个对象实体。C++的引用计数作为内存管理的方法和技术手段主要有一下两个作用。 (1)简化了堆对象(heap objects)的管理。 一个对象被从堆中分配出来之后,需要明确知道是谁拥有了这个对象,因为只有拥有这个对象的所有者才能够销毁它。但在实际使用过程中, 这个对象可

Doublelv 的博客专栏。 4445

FreeRTOS实战:STM32CubeMX配置USART+DMA实现高效串口通信(附完整代码)

本文详细介绍了如何使用FreeRTOS和STM32CubeMX配置USART与DMA实现高效串口通信。通过对比轮询、中断和DMA三种模式的性能差异,提供完整的STM32CubeMX配置步骤和代码实现,帮助开发者优化嵌入式系统的串口通信性能,显著提升数据吞吐量和系统响应速度。

weixin_29190169的博客 456

python使用TensorRT报错,多线程或多进程中使用问题

python使用TensorRT报错,Cuda Runtime问题

qq_44224801的博客 747

C++ | 引用详解

引用是 C++中的一种类型,它为已存在的对象提供了一个别名。引用不是一个独立的对象,它必须在创建时被初始化,并且一旦初始化,它就一直绑定到那个特定的对象。引用的主要目的是提供一种更方便、更安全的方式来操作对象,避免不必要的复制和指针操作的复杂性。C++引用是一种强大的工具,它为我们提供了一种方便、高效的方式来操作对象。引用的主要特点包括必须初始化、与原始对象具有相同的内存地址、没有独立的存储空间以及在参数传递和返回值方面的高效性。与指针相比,引用具有更简单的语法和更安全的操作方式。

TTKunn的博客 2418

【WRF安装】完整自动化 WRF-ARW/WRF-Chem 安装脚本(多服务器测试)

【WRF安装】完整自动化 WRF-ARW/WRF-Chem 安装脚本(多服务器测试)

WW、forever的博客 285

C++基础-引用详解(全网最详细,看这篇就够了)

本节我们正式进入C++之引用的学习,下面小编将会带领大家由浅入深逐步解剖引用的语法及应用场景,话不多说,我们直接上干货!!

2302_79341182的博客 3016

分析4-20mA检查电路分析

本文介绍了一种工业领域常用的4-20mA电流信号调理电路,可将标准电流信号转换为适合MCU采集的电压信号。电路包含三个关键模块:首先通过10Ω取样电阻将4-20mA电流转换为0.04-0.2V电压;然后采用同向比例运算放大器KTA333-ST5进行信号放大;最后通过二阶有源低通滤波器滤除工业环境中的高频干扰。文章详细分析了各模块的工作原理和参数设计,并以压力传感器和温度变送器为例说明了实际应用中的参数调整方法。该电路具有抗干扰能力强、精度高等特点,适用于工业压力、温度等模拟量信号的采集处理。

qq_37999850的博客 1331

Qualcomm 常用NV列表

^ NV ITEM ^ 功能^^ |NV10 |mode prefer,找网模式|新平台使用NV80000| ^NV74 NV74=0关闭自动接听电话^ |NV240 |NV240=FALSE|EVDO出现网络的问题,此项必须设定为FALSE| |NV255 |CDMA规避网络列表(SID/NID号)| |NV256 |

sdrgtywretyeruet的专栏 5771

大模型之Spring AI实战系列(二十六):Spring Boot + DeepSeek 实战指南:构建AI聊天应用

在人工智能技术飞速发展的今天,大型语言模型已经成为了推动技术创新的重要力量。DeepSeek作为国内领先的大型语言模型提供商,其推出的DeepSeek系列模型在多个领域都展现出了卓越的性能。本文将详细介绍如何使用Spring Boot框架集成DeepSeek API,构建一个简单的AI聊天应用。我们将实现两个核心功能:普通文本生成和流式文本生成。

寻道AI,探索AI无限可能! 2264

C++引用计数原理和实现

为什么80%的码农都做不了架构师?>>> ...

weixin_34221073的博客 2061

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

仿照现代 C++ 智能指针实现自己的引用计数「上」

虽然标准库已经提供非常多现成的智能指针可供调用,但是其中的奥妙还是非常值得我们细细揣摩,下面就开始跟随笔者一起实现自己的引用计数帮助类,权当作略微简陋的自定义智能指针。

2301_76403635的博客 1107

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

狗尾续貂:利用引用计数在多线程中安全释放资源

原文标题:IOCP中的socket错误和资源释放处理方法 原文作者:sodme原文地址:http://blog.csdn.net/sodme/archive/2006/04/17/666062.aspx原作者声明:本文可以不经作者同意任意转载、复制、传播,但任何对本文的引用均须保留本文的作者、出处及本行声明信息!谢谢! 本文是观大宝SODME的BLOG中文章有感,原文中提到了两种方法(对数据

于无声处 7381

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

引用计数

最近在看《提高c++性能的编程技术》一书,第十二章提到引用计数,要开始学习新知识了~ 学习之前先抄录书中一段精彩的言论(P177) -------------------------------------------------------- 类似于自然界,熵的原理亦可用于软件工程之中--所有实体都会随着时间的消逝而消失。一个软件项目最初可能源起于某个设计清晰、实现简单的小型原型系统。只包...

weixin_33830216的博客 87

引用计数(Reference Counting)和拷贝时写入并代理(CopyOnWrite&Proxy)的应用 (转载)

引子    如果让你用C++写一个实用的字符串类,我想下面的方案是很多人最先想到的:class ClxString{public:    ClxString();    ClxString(const char *pszStr);    ClxString(const ClxString &str);    ClxString& operator=(const ClxString &str

Herbert8888的专栏 786

GC基本算法及C++GC机制

转载:https://www.cnblogs.com/QG-whz/p/5079638.html 前言 垃圾收集器是一种动态存储分配器,它自动释放程序不再需要的已分配的块,这些块也称为垃圾。在程序员看来,垃圾就是不再被引用的对象。自动回收垃圾的过程则称为垃圾收集(garbage collection)。在一个支持垃圾收集的语言中,程序显式地申请内存,但从不需要显式的释放它们。垃圾收集器会定期识别垃圾块,并将垃圾块放回空闲链表中。显然,C语言的malloc包不是一个带GC功能的分配器,程序员显式 调用ma

知识无止境 3536

【GC Algorithm】引用计数算法

(文章参考http://www.2cto.com/kf/201110/108419.html) 【概述】 引用计数(Reference Counting)算法是每个对象计算指向它的指针的数量,当有一个指针指向自己时计数值加1;当删除一个指向自己的指针时,计数值减1,如果计数值减为0,说明已经不存在指向该对象的指针了,所以它可以被安全的销毁了(回收)。可以很直观的用下面的图表示: ...

weixin_30478757的博客 120

转载知乎 C++后台开发面试一般考察什么

https://www.zhihu.com/question/34574154?sort=created作者:Oscarwin链接:https://www.zhihu.com/question/34574154/answer/253165162来源:知乎著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。C和C++语言基础参考书籍:《C++ primer》,《effective C...

qq_38847853的博客 4190

Netty之引用计数器

转载:http://calvin1978.blogcn.com/articles/netty-leak.html引用计数器的必要性  在内存池的场景中,ByteBuf不再使用时需要主动归还给内存池;引用计数器相关知识 ByteBuf被创建时,引用计数的初始值为1; 调用release(),计数器减1,当计数器等于零时, deallocate()被调用,回收资源; 调用release()或者retai

04stone37 706

C++智能指针(转载)

今天才知道这种内存管理机制有个专属名词——“智能指针”,out了……转载: C++技巧(标准auto_ptr智能指针机制  很多人听说过标准auto_ptr智能指针机制,但并不是每个人都天天使用它。这真是个遗憾,因为auto_ptr优雅地解决了C++设计和编码中常见的问题,正确地使用它可以生成健壮的代码。本文阐述了如何正确运用auto_ptr来让你的

岁月留痕 1068

引用计数和AddRef、Release

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34216107的博客 93

C++智能指针应用方式体验

自己的项目中大量使用到了智能指针(非标准库中的),没办法,硬着头皮研究了一下午,才大致有点思路。今天一整天实在头疼(估计曹操当年就这么疼的吧. ^_^),破例九点多就睡觉... 原文地址:http://developer.51cto.com/art/201002/183350.htm C++语言对于C语言 功能的支持是完全的,它不但具有这些功能,而且还能在其基础上更加优化这些强大的功能。在...

weixin_34023982的博客 1020

详解C++11智能指针(转载)

https://www.cnblogs.com/WindSun/p/11444429.html原文链接 前言 C++里面的四个智能指针: auto_ptr, unique_ptr,shared_ptr, weak_ptr 其中后三个是C++11支持,并且第一个已经被C++11弃用。 C++11智能指针介绍 智能指针主要用于管理在堆上分配的内存,它将普通的指针封装为一个栈对象。当栈对象的生存周期结束后,会在析构函数中释放掉申请的内存,从而防止内存泄漏。C++ 11中最常用的智能指针类型为sha..

luobaotai的博客 198
上一篇: 【POJ2761】【区间第k大】Feed the dogs(吐槽)
下一篇: 【POJ3481】【splay】Double Queue
Gregory99174
博客等级 码龄10年 2粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值