C++新特性16_写时拷贝(解决浅拷贝在某一个类对象中的资源进行修改,所有引用该资源的对象全部会被修改的问题;解决办法:在所有改变值的地方,重新分配内存,改变的是拷贝的值,而不影响原有对象中共享资源)

2023-11-07


接上篇内容遗留了两个问题,第一个问题及解决方法如下:

1. 问题:如果共享资源中的值发生了变化,那么其他使用该共享资源的值如何保持不变?

下图中将"li si"改为"li si2"后,两个对象指向的内容都同时发生改变。
在这里插入图片描述

2. 解决思路:使用引用计数时,当发生共享资源值改变的时候,需要对其资源进行重新的拷贝,这样改变的是拷贝的值,而不影响原有的对象中的共享资源。

写时拷贝(COW copy on write),在所有需要改变值的地方,重新分配内存。涉及资源的拷贝和引用计数的加减(原引用计数减1,新的引用计数变为1)


#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;

struct RefValue
{

	RefValue(const char* pszName);
	~RefValue();

	void AddRef();
	void Release();

	char* m_pszName;
	int   m_nCount;//利用普通的变量作为计数器
};

RefValue::RefValue(const char* pszName)
{
	m_pszName = new char[256];

	strcpy(m_pszName, pszName);
	m_nCount = 1;

}

RefValue::~RefValue()
{
	if (m_pszName != NULL)
	{
		delete m_pszName;
		m_pszName = NULL;
	}
}

//计数器加1函数
void RefValue::AddRef()
{
	m_nCount++;
}

void RefValue::Release()
{
	if (--m_nCount == 0)
	{
		delete this;
	}

}


class CStudent
{
public:
	CStudent(const char* pszName);
	CStudent(CStudent& obj);

	void SetName(const char* pszName);

	~CStudent();

	CStudent& operator=(CStudent& obj); main中采用stu1 = stu2;这种形式时才会调用=运算符重载

	void release();

	void Show()
	{
		if (m_pValue->m_nCount > 0)
		{
			cout << hex << (int&)m_pValue->m_pszName << m_pValue->m_pszName << endl;
		}
	}

private:
	RefValue* m_pValue;
};

void CStudent::SetName(const char* pszName)
{
	m_pValue->Release();//原来的计数器处理
	m_pValue = new RefValue(pszName);//创建一个新的计数器
}

CStudent::CStudent(const char* pszName)
{
	m_pValue = new RefValue(pszName);
}

//构造的时候浅拷贝,计数器加1
CStudent::CStudent(CStudent& obj)
{
	m_pValue = obj.m_pValue;
	m_pValue->AddRef();
}

CStudent::~CStudent()
{
	release();
}

//=运算符重载的时候浅拷贝,计数器加1
CStudent& CStudent::operator=(CStudent& obj)
{
	if (obj.m_pValue == m_pValue)
	{
		return *this;
	}

	m_pValue->Release();

	m_pValue = obj.m_pValue;
	m_pValue->AddRef();

	return *this;
}

void CStudent::release()
{
	m_pValue->Release();
}

int main(int argc, char* argv[])
{
	CStudent stu1("zhang san");

	CStudent stu2("li si");

	CStudent stu3 = stu2;


	stu2.Show();
	stu3.Show();

	stu2.SetName("li si2");//释放与新建计数器

	stu2.Show();
	stu3.Show();

	return 0;
}

上面程序中的核心就在于:

void CStudent::SetName(const char* pszName)
{
    //原来的计数器处理,计数器减一后判断是否为0,是0则释放
	m_pValue->Release();
	m_pValue = new RefValue(pszName);//创建一个新的计数器,表示复制之后的对象
}

//计数器减一后判断是否为0,是0则释放
void RefValue::Release()
{
	if (--m_nCount == 0)
	{
		delete this;
	}

}

//创建一个新的计数器
RefValue::RefValue(const char* pszName)
{
	m_pszName = new char[256];

	strcpy(m_pszName, pszName);
	m_nCount = 1;

}

程序运行之后就可以实现stud2改变资源之后,不会改变sud3的资源,实现写时拷贝。

3. 学习视频地址:写时拷贝
4. 学习笔记:写时拷贝笔记

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++新特性16_写时拷贝(解决浅拷贝在某一个类对象中的资源进行修改,所有引用该资源的对象全部会被修改的问题;解决办法:在所有改变值的地方,重新分配内存,改变的是拷贝的值,而不影响原有对象中共享资源) 的相关文章

  • IIS应用程序池回收+quartz调度

    我正在 IIS 7 5 上运行一个 Web 应用程序 它需要偶尔回收 否则内存使用情况会失控 这是我正在研究的问题 当它回收时 它实际上不会运行 直到另一个请求到来 而quartz不会运行 有没有办法让IIS在回收应用程序池后立即自动启动1
  • C# 打印问题(RichTextBox)

    我想打印我的 RichTextBox eintragRichTextBox 的内容 我现在有这个代码 private void druckenPictureBox Click object sender EventArgs e PrintD
  • 使用 CLion 进行 OpenCV Windows 设置

    我想在 Windows 上为 CLion IDE 设置 OpenCV 我尝试使用 OpenCV 3 1 和 2 4 得到相同的结果 我有 Windows 10 64 位 CLion 使用 cygwin 环境 到目前为止我做了什么 1 从Op
  • CMake 找不到请求的 Boost 库

    既然我已经浏览了其他人的解决方案几个小时 但找不到适合我的问题的正确答案 我想将我的具体问题带给您 我正在尝试使用 CMake 构建 vsomeip 为此 我之前构建了 boost 1 55 但是 我在 CMake 中收到以下错误 The
  • 将 new 与 decltype 一起使用

    T t T is an implementation detail t new T want to avoid naming T to allow for flexibility t new decltype t error cannot
  • 单元测试验证失败

    我正在运行我的单元测试PostMyModel路线 然而 在PostMyModel 我用的是线Validate
  • C++ 长 switch 语句还是用地图查找?

    在我的 C 应用程序中 我有一些值充当代表其他值的代码 为了翻译代码 我一直在争论使用 switch 语句还是 stl 映射 开关看起来像这样 int code int value switch code case 1 value 10 b
  • CSharpRepl emacs 集成?

    我碰巧知道莫诺CSharpRepl http www mono project com CsharpRepl 是否有 emacs csharp 模式使用它在一个窗口中运行 REPL 并像 python 模式一样在另一个窗口中编译 运行 C
  • 在 C# 中调用 C++ 库 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我有很多用 C 编写的库 我想从 C 调用这些库 但是 我遇到了很多问题 我想知道是否有书籍或指南告诉我如何做到这一点 Dll导入 htt
  • 是否存在指向不同类型的指针具有不同大小的平台?

    C 标准允许指向不同类型的指针具有不同的大小 例如sizeof char sizeof int 是允许的 但是 它确实要求如果将指针转换为void 然后转换回其原始类型 它必须与其原始值进行比较 因此 从逻辑上来说 sizeof void
  • C# 开源 NMEA 解析器 [已关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找 C 开源 NMEA 解析器 嗯 我自己也不熟悉 但是一些快速搜索显示了一个代码项目 htt
  • 将表(行)与 OpenXML SDK 2.5 保持在一起

    我想在 Word 文档中生成多个表 每行 2 行 但我想将这两行保留在一起 如果可能的话 new KeepNext 第一行不起作用 new KeepNext 第一行的最后一段不起作用 new CantSplit 放在桌子上不起作用 在所有情
  • 使用 LINQ 更新 IEnumerable 对象的简单方法

    假设我有一个这样的业务对象 class Employee public string name public int id public string desgination public int grade List
  • 使用查询表达式对 List 进行排序

    我在使用 Linq 订购这样的结构时遇到问题 public class Person public int ID get set public List
  • 根据对象变量搜索对象列表

    我有一个对象列表 这些对象具有三个变量 ID 名称和值 这个列表中可能有很多对象 我需要根据ID或Name找到一个对象 并更改值 例子 class objec public string Name public int UID public
  • 如何在三个 IEnumerable 上使用 Zip [重复]

    这个问题在这里已经有答案了 可能的重复 使用 Linq 从 3 个集合创建项目 https stackoverflow com questions 5284315 create items from 3 collections using
  • C#6 中的长字符串插值行

    我发现 虽然字符串插值在应用于现有代码库的字符串 Format 调用时非常好 但考虑到通常首选的列限制 字符串对于单行来说很快就会变得太长 特别是当被插值的表达式很复杂时 使用格式字符串 您将获得一个可以拆分为多行的变量列表 var str
  • 析构函数中的异步操作

    尝试在类析构函数中运行异步操作失败 这是代码 public class Executor public static void Main var c1 new Class1 c1 DoSomething public class Class
  • 通过 Tab 键浏览 XML 文档字段

    In VB NET you can move through the fields in the XML member documentation with the Tab key 这在 C 中不起作用 还有其他方法吗 除了用鼠标将光标放在
  • DataContractSerializer 事件/委托字段问题

    在我的 WPF 应用程序中 我正在使用DataContractSerializer序列化对象 我发现它无法序列化具有事件或委托声明的类型 考虑以下失败的代码 Serializable public abstract class BaseCl

随机推荐

  • Spark组件:RDD、DataFrame和DataSet介绍、场景与比较

    1 rdd dataframe dataset在哪个版本被引入 2 什么情况下使用rdd dataframe dataset 3 它们有什么不同 spark生态系统中 Spark Core 包括各种Spark的各种核心组件 它们能够对内存和
  • 数字后端知识点扫盲——芯片harden block的划分

    后端在floorplan阶段 如何摆放macro是一个很重要的问题 如果采用层次化设计 对于每一个block来说都需要在block内部把锁分配的macro摆好 如果某一个block里的macro很多 而且又很大 std cell再多一些 这
  • Lattice 开发工具Diamond 相关版本下载地址

    百度网盘 https wenku baidu com view 21b98975192e45361066f5f3 html 官网下载 http www latticesemi com Support SoftwareArchive aspx
  • 'DataFrame' object has no attribute 'dtype'

    这个错误消息的意思是 在你的代码中 你试图访问一个Pandas DataFrame对象的 dtype 属性 但该对象并没有这个属性 在Pandas中 DataFrame没有 dtype 属性 你可以使用 dtypes 属性来获取DataFr
  • 在vs2019配置MySQL环境,不需要每次新建一个项目重新配置的方法(图文详解)

    目录 问题 解决方法 问题 上一期讲到怎么在vs2019去配置mysql的编译环境vs2019 c c 配置MySQL数据库的环境 图文详解 守约斯维奇的博客 CSDN博客 这里我们会觉得当建立一个新项目的时候去配置mysql的编译环境非常
  • Qt D-Bus

    介绍 D Bus是为Linux系统开发的进程间通信 IPC 和远程过程调用 RPC 机制 使用统一的通信协议来代替现有的各种IPC解决方案 它允许系统级进程 如 打印机和硬件驱动服务 和普通用户进程进行通信 它使用一个快速的二进制消息传递协
  • 分布式理论-拜占庭将军(译)

    作者 LESLIE LAMPORT ROBERT SHOSTAK and MARSHALL 1982 译者 phylips bmy 出处 http duanple blog 163 com blog static 7097176720112
  • springBoot 拦截器

    声明 代码是JavaEE开发的颠覆者 Spring Boot实战代码中的 我买了这书 并练习 public class DemoInterceptor extends HandlerInterceptorAdapter 1 Override
  • 笔录getResource() 与 getClassLoader().getResource()

    结论 1 Class getResource String path path路径的前缀不是 表示从此类所在的包下取资源文件 path路径的前缀是 则是从ClassPath根下获取资源文件 Class getResource和Class g
  • python seleium b站 自动投币脚本

    主要是给我的投币器做个铺垫 果然软件还是太容易了 难在硬件和外壳好吗 1 把edge的调试端口打开 添加以下参数 C Program Files x86 Microsoft Edge Application msedge exe remot
  • 在express项目里配置ejs模板引擎

    方法1 修改app js view engine setup app set views path join dirname views app set view engine ejs 在views中创建ejs模板文件 方法2 修改app
  • 老年人晕倒的几种原因

    晕倒是一种突发性 短暂性 一过性的意识丧失而昏倒 突然性的晕倒 跟大脑的神经有分不开关系 癫痫 脑供血不足 心脑血管疾病都是引起头晕倒的原因 大脑血液上不来 脑血液突然停止 就会产生放电波头晕的症状 患者会在一时间出现晕倒 很容易引起脑震荡
  • 在conda虚拟环境中的PyQt配置以及相关Pycharm设置

    文章目录 在conda虚拟环境中的PyQt配置 背景环境介绍 PyQt依赖包及PyQt tools的下载 Pycharm进行PyQt的相关配置 结语 在conda虚拟环境中的PyQt配置 作者 下龙湾 背景环境介绍 anaconda安装文件
  • Netty4简单认知

    Channel简介 在Netty中 Channel相当于一个Socket的抽象 它为用户提供了关于Socket状态 是连接还是断开 及对Socket的读 写等操作 每当Netty建立了一个连接 都创建一个与其对应的Channel实例 Cha
  • 各种排序算法的讲解与实现

    排序的分类 1 内部排序 内部排序 在整个排序过程中不需不访问外存便能完成 称这样的排序问题为内部排序 1 1 插入排序 插入排序 将无序序列中的一个或几个记录 插入 到有序的序列中 从而增加记录的有序序列的长度 主要思想是将第一个元素看做
  • 3D重建模的初步了解

    相关学习资料如下 cousera课程 https www coursera org learn robotics perception youtube课程 https www youtube com watch v RDkwklFGMfo
  • 什么是HTTPS

    首先 在参考 Tomcat内核设计剖析 大型网站技术架构 的基础上加了一些个人理解 如有错误或者不全面的地方 还请大家指出 在知道什么是HTTPS之前 我们首先要知道一下什么是HTTP HTTP是超文本传输协议的简称 工作在应用层 传输层基
  • linux上好玩的东西

    Figlet 想知道tmux安装与配置评论加点赞 想要我这个效果吗 安装figlet mac安装 brew install figlet brew 没有的可以看我之前的文章 ma配置 linux ubuntu deepin sudo apt
  • 最易上手的测试用例设计方法

    NO 1 lt lt 测试用例设计方法 gt gt 以下是八种常见的测试用例设计方法 包括等价类 边界值 判定表 因果图 正交实验 状态迁移图 场景法和错误推测 详述如下 等价类划分法 Equivalence Partitioning 策略
  • C++新特性16_写时拷贝(解决浅拷贝在某一个类对象中的资源进行修改,所有引用该资源的对象全部会被修改的问题;解决办法:在所有改变值的地方,重新分配内存,改变的是拷贝的值,而不影响原有对象中共享资源)

    C 新特性16 写时拷贝 1 问题 如果共享资源中的值发生了变化 那么其他使用该共享资源的值如何保持不变 2 解决思路 使用引用计数时 当发生共享资源值改变的时候 需要对其资源进行重新的拷贝 这样改变的是拷贝的值 而不影响原有的对象中的共享