C++引用计数

news2024/11/16 3:14:56

文章目录

  • 1. 什么是引用计数
  • 2. 引用计数的实现
  • 3. 示例代码

1. 什么是引用计数

引用计数(reference count)的核心思想是使用一个计数器来标识当前指针指向的对象被多少类的对象所使用(即记录指针指向对象被引用的次数)。它允许有多个相同值的对象共享这个值的实现。引用计数的使用常有两个目的:

  • 简化跟踪堆中(也即C++中new出来的)的对象的过程。一旦一个对象通过调用new被分配出来,记录谁拥有这个对象是很重要的,因为其所有者要负责对它进行delete。但是对象所有者可以有多个,且所有权能够被传递,这就使得内存跟踪变得困难。引用计数可以跟踪对象所有权,并能够自动销毁对象。可以说引用计数是个简单的垃圾回收体系。

  • 节省内存,提高程序运行效率。如果很多对象有相同的值,为这多个相同的值存储多个副本是很浪费空间的,所以最好做法是让左右对象都共享同一个值的实现。C++标准库中string类采取一种称为”写时复制“的技术,使得只有当字符串被修改的时候才创建各自的拷贝,否则可能(标准库允许使用但没强制要求)采用引用计数技术来管理共享对象的多个对象。

2. 引用计数的实现

使用引用计数实现智能指针的关键是,引用计数应该存在哪里。引用计数应该是某个类对象和其复制对象共享的, 而指针成员恰好有这样的特性, 故可以在类中多声明一个size_t* 的成员,用来表示引用计数。

  • 构造函数中创建类的新对象时,初始化引用计数为1;
  • 拷贝构造函数复制指针,并使相应的引用计数增加1;
  • 赋值操作减少左操作数所指对象的引用计数,增加右操作数所指对象的引用计数;
  • 析构函数使引用计数减少1,并且当引用计数为1时,释放指针所指向的对象;

在这里插入图片描述

3. 示例代码

#include <iostream>
#include <string>

using std::string; using std::ostream; using std::cout; using std::size_t;

class HasPtr {
	friend ostream& print(ostream&, const HasPtr&);
public:
	// string():构造空的string类对象,既空字符串
	HasPtr(const string& s = string()) : ps(new string(s)), i(0), use(new size_t(1)) { } // constructor
	~HasPtr(); // 析构函数
	HasPtr(const HasPtr& rhs) : ps(rhs.ps), i(rhs.i), use(rhs.use) { ++* use; } // 拷贝构造函数
	HasPtr& operator=(const HasPtr&); // 运算符重载
private:
	string* ps; // ps是一个指针,指向string类型
	int i;
	size_t* use; // use是一个指针,指向size_t类型
};

// 析构函数的定义
HasPtr::~HasPtr()
{
	if (-- * use == 0) {	// 如果引用计数为变0
		delete ps;			// 释放string内存
		delete use;			// 释放计数器内存
	}
}

// 运算符重载的定义
HasPtr&
HasPtr::operator=(const HasPtr& rhs)
{
	++* rhs.use;			// 递增右侧运算对象的引用计数
	if (-- * use == 0) {	// 然后递减本对象的引用计数
		delete ps;			// 如果没有其他用户
		delete use;			// 释放本对象分配的成员
	}
	ps = rhs.ps;			// 将数据从rhs拷贝到本对象
	i = rhs.i;
	use = rhs.use;
	return *this;			// 返回本对象
}

// 友元函数的定义
ostream& print(ostream& os, const HasPtr& p)
{
	os << p.ps << ' ' << *p.ps << ' ' << *p.use;
	return os;
}

void func(const HasPtr& p)
{
	HasPtr temp;
	temp = p;
	cout << "p: ";
	print(cout, p) << '\n';;
	cout << "temp: ";
	print(cout, temp) << '\n';;
}

int main()
{
	cout << "HasPtr str1(\"copy me\"), str2;\n";
	HasPtr str1("copy me"), str2;
	cout << "str1: ";
	print(cout, str1) << '\n';
	cout << "str2: ";
	print(cout, str2) << '\n';

	cout << "\nstr2 = str1;\n";
	str2 = str1;
	cout << "str1: ";
	print(cout, str1) << '\n';
	cout << "str2: ";
	print(cout, str2) << '\n';
	
	cout << "\nfunc(str1);\n";
	func(str1);
	
	cout << "\nstr1: ";
	print(cout, str1) << '\n';
	cout << "str2: ";
	print(cout, str2) << '\n';
	return 0;

}

输出结果:

HasPtr str1("copy me"), str2;
str1: 0116D990 copy me 1
str2: 011654E8  1

str2 = str1;
str1: 0116D990 copy me 2
str2: 0116D990 copy me 2

func(str1);
p: 0116D990 copy me 3
temp: 0116D990 copy me 3

str1: 0116D990 copy me 2
str2: 0116D990 copy me 2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/707899.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux--查找文件指令:find

语法&#xff1a; find pathname -name 文件名 示例&#xff1a; 从根目录下开始查找名字中带file.txt文件的路径

C++思维导图以及作业

定义一个命名空间Myspace&#xff0c;包含以下函数&#xff1a;将一个字符串中的所有单词进行反转&#xff0c;并输出反转后的结果。例如&#xff0c;输入字符串为"Hello World"&#xff0c;输出结果为"olleH dlroW"&#xff0c;并在主函数内测试该函数。 …

战略书籍排行榜前五名

战略管理对企业的重要性不言而喻。有效的战略管理可以帮助企业确定未来的方向和目标、制定长期发展规划、提高企业的竞争力和获得市场份额。本文推荐的这5本优秀的战略管理类书籍&#xff0c;每一本都有其独特的思想和实践价值&#xff0c;值得企业管理者借鉴和学习。 战略书籍…

Leetcode---351周赛

周赛题目 2748. 美丽下标对的数目 2749. 得到整数零需要执行的最少操作数 2750. 将数组划分成若干好子数组的方式 2751. 机器人碰撞 一、美丽下标对的数目 这题没什么好说的&#xff0c;按照题目的要求直接暴力求解&#xff0c;代码如下 bool gcd(int x,int y){if(x1||y1)…

vue父子组件之间相互控制传值,子组件使用$parent直接控制父组件的值

父子组件之间相互控制传值&#xff0c;子组件控制父组件的值 需求概述 父组件在提交表单后&#xff0c;弹框进行提示&#xff0c;子组件是一个弹框。 vue版本 v2.x 实现原理 在父组件内建立控制器isShowModal&#xff0c;使用v-if来控制子组件的显示与隐藏。在子组件通过…

DAY39——动态规划part2

1.考虑障碍在起点和终点的特殊状况&#xff0c;可直接返回0 2.判断是否存在障碍物&#xff1a;初始化时需要设置障碍物后的坐标为0

常见存储引擎

TiKV 简介 TiKV 是一个分布式事务型的键值数据库&#xff0c;提供了满足 ACID 约束的分布式事务接口&#xff0c;并且通过Raft协议保证了多副本数据一致性以及高可用。TiKV 作为 TiDB 的存储层&#xff0c;为用户写入 TiDB 的数据提供了持久化以及读写服务&#xff0c;同时还存…

Spring BeanFactory FactoryBean的区别?

文章目录 前言一、BeanFactory二、FactoryBean 前言 面试中被问到过Spring BeanFactory FactoryBean的区别&#xff1f;当时没答上来&#xff0c;感觉这就是一个文字游戏&#xff0c;后面仔细的了解了一下&#xff0c;分享给大家。 一、BeanFactory 在 Spring 中最核心的就是…

GDB 断点管理

1、b 设置断点 usage 1: b 函数名 usage 2: b 文件名:行号 2、rb 函数名关键字 &#xff1a; 所有带有这个关键字的函数名都设置为断点 (gdb) rb dkauth Breakpoint 7 at 0x34187ae0: file /home/jintao/cvf/apps/cvf/services/dkauth/src/dkauth.c, line 58. void dkauth_…

Python之花舞盛宴:探索列表与元组之美与妙用

前言 在Python编程世界中&#xff0c;列表和元组是两个最常用的数据结构之一。无论是初学者还是经验丰富的开发者&#xff0c;对于这两个数据类型的掌握都至关重要。 列表和元组都是用于存储多个值的容器&#xff0c;但它们在性质和特性上有所不同。列表是可变的&#xff0c;…

VMIC-pci-5565反射内存的优势

优势&#xff1a; &#xff08;1&#xff09;实现远程互连的能力 随着仿真实验复杂度的提高&#xff0c;需要多楼宇多试验室间设备的远程互连&#xff0c;通过单模光纤及光纤HUB将远距离的试验室设备进行连接&#xff0c;单模光纤支持的传输距离可达20km。对于距离300m以内的试…

免费搭建一个有脾气的聊天机器人,1行Python代码就够了!

大家好&#xff0c;这里是程序员晚枫。 之前在小破站&#xff1a;Python自动化办公社区给大家免费分享了用Python制作一个wx机器人&#xff0c;1行代码人人可用&#xff0c;很多人还想要免费的智能聊天功能。 今天终于开发出来了&#xff0c;让我们一起看一下&#xff0c;如何…

第四课—大学英语四六级备考—听力专项

Key Words 1.monarch n.君主政治 非常抱歉误解了您的问题。以下是关于"monarch"这两个意义的常见用法、造句和固定搭配的例子&#xff1a; 1. Monarch&#xff08;君主&#xff09;&#xff1a; - 造句&#xff1a; - The monarch of the country made an…

爆文:硬件工程师如何零基础入门?

大家好&#xff0c;我是记得诚。 最近老是有读者问我学习路线&#xff0c;之前其实写过一篇文章&#xff1a; 硬件工程师如何零基础入门&#xff1f;&#xff08;点击阅读&#xff09; 觉得很有必要再发一遍&#xff0c;这篇文章&#xff0c;在全网也算爆文了。 在CSDN有65…

SpringBoot项目中PageHelper给子查询做分页

目录 1.起因 2.sql改进 3.改造pagehelper 4.新的问题 方案一 方案二 方案三(终极) 5.附上pagehelper官方使用指南 1.起因 项目中有个查询非常慢,查询第一页都很慢, sql为一张大表A left join了许多张基础数据表(小表), select * from A left join b on xxx left join…

安全、环保的随身“数据库”——体验希捷锦系列移动硬盘

移动硬盘不属于那种技术更新换代快、差异化明显的产品&#xff0c;因此消费者在选购时关注的点无外乎容量、价格、外观、传输速度以及数据安全等方面。希捷新推出的锦系列移动硬盘&#xff0c;就聚焦数据安全&#xff0c;同时在选材上贯彻了环保理念&#xff0c;设计方面也值得…

Linux限制用户使用特权-限制su

Linux下&#xff0c;允许普通用户通过su命令切换到root身份进行操作。 相对于直接使用root登录操作&#xff0c;这钟方法要安全些。但仍存在安全隐患。 缩小特权使用用户的范围&#xff0c;无疑是更安全的做法。 Linux提供了这样的设置。 编辑/etc/pam.d/su文件&#xff0c…

ai绘画工具有免费的吗?3款ai画图工具分享

在ai绘画工具问世之后&#xff0c;我试验了各种软件&#xff0c;有的功能太过简单&#xff0c;无法满足我对创作的要求&#xff1b;有的则要求我花费大额费用才能享受完整的功能。这让我在探索过程中一度怀疑是否真的有免费软件能够满足我的需求。 然而功夫不负有心人&#xf…

MySQL数据库——MHA高可用

MySQL数据库——MHA高可用 一、MHA概述1&#xff0e;什么是 MHA2&#xff0e;MHA 的组成3&#xff0e;MHA 的特点 二、搭建 MySQL MHA1.Master、Slave1、Slave2 节点上安装 mysql5.72&#xff0e;修改 Master、Slave1、Slave2 节点的主机名&#xff0c;添加主从mysql的映射关系…

数据结构--栈的引用--前中后缀表达式(后部分)

数据结构–栈的引用–前中后缀表达式(后部分) 中缀表达式转后缀表达式&#xff08;手算) 中缀转后缀 \color{purple}中缀转后缀 中缀转后缀的 手算方法 \color{purple}手算方法 手算方法: ①确定中缀表达式中 各个运算符的运算顺序 \color{red}各个运算符的运算顺序 各个运算符…