C++ 深浅拷贝、写时拷贝

2023-11-09

前言:本章以string类为例介绍浅拷贝与深拷贝,引用计数写时拷贝作为了解内容,string类的模拟实现参考C++ string类的模拟实现


1.浅拷贝

浅拷贝:对于有申请空间的对象的类来说,是按照字节序依次拷贝过去的,并没有另外申请一块空间。因此,在调用析构函数的时候会造成同一块空间释放两次的情况,从而使程序崩溃。

如下实例:

class string
{
public:
	string(const char* str)
	{
		//构造string类对象时,如果传递nullptr指针
		//认为程序非法,此处断言下
		assert(str);

		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}
	~string()
	{
		if (_str)
		{
			delete[] _str;
			_str = nullptr;
		}
	}

private:
	char* _str;
};

void test()
{
	string s1("linmanman");
	string s2(s1);
}

运行看看,报错了

image-20211119153738386

分析错因:

image-20211119155522526

image-20211119160321325

浅拷贝是指向同一块空间的,这样就会有俩个无法避免的问题:

1.析构俩次空间,程序崩溃

2.其中一个的值被修改了,会影响到另外一个的值。

深拷贝:给每个对象单独分配资源,就是给待拷贝的对象另开一片空间,再把原对象空间上的值拷贝过来,这样在调用析构函数的时候就不会产生冲突。

image-20220213125937937

image-20211119160705278


2.深拷贝

传统写法的string类的深拷贝是自己开空间,自己将拷贝的对象拷贝到待拷贝对象中。

string(const string& s)
 : _str(new char[strlen(s._str)+1])
 {
 strcpy(_str, s._str);
 }
 
 string& operator=(const string& s)
 {
 if(this != &s)
 {
 char* pStr = new char[strlen(s._str) + 1];
 strcpy(pStr, s._str);
 delete[] _str;
 _str = pStr;
 }
 return *this;
 }

现代写法的string类的深拷贝堪称是“移花接木”

string(const string& s)
	:_str(nullptr)//必须置空,因为_str开始是个随机数,交换给tmp._str后,释放会引起问题
{
	string tmp(s._str);//直接利用构造函数,给tmp对象开辟了一块空间
	swap(tmp);
}

string& operator=(string s)
{
	swap(s);//这个swap是咱们自己写的哦

	return *this;
}

顺带提一嘴,各个编译器深拷贝的底层实现略有差异(当然逻辑是一样的)

VS 2013下的深拷贝

image-20220213130133785

g++下的深拷贝

image-20220213130200116


3.引用计数+写时拷贝

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

image-20220803225112988

解决思路:使用引用计数时,当发生共享资源值改变的时候,需要对其资源进行重新拷贝,这样改变拷贝的值时,不会对共享资源造成影响。

image-20220803225607327

写时拷贝,在所有需要改变值的地方,重新分配内存。

写时拷贝就是一种拖延症, 是在浅拷贝的基础之上增加了引用计数的方式来实现的。

引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该对象时资源的最后一个使用者, 将该资源释放;否则就不能释放,因为还有其他对象在使用该资源。

image-20220213130242526

写时拷贝不多介绍了,感兴趣的朋友可以阅读下陈皓大佬写的这两篇博客,深度相当够了!

写时拷贝博客推荐

写时拷贝读取时的缺陷


感谢您的阅读!!!如果内容对你有帮助的话,记得给我三连(点赞、收藏、关注)——做个手有余香的人。

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

C++ 深浅拷贝、写时拷贝 的相关文章

  • C 编程 - 文件 - fwrite

    我有一个关于编程和文件的问题 while current NULL if current gt Id Doctor 0 current current gt next id doc current gt Id Doctor if curre
  • Web 客户端和 Expect100Continue

    使用 WebClient C NET 时设置 Expect100Continue 的最佳方法是什么 我有下面的代码 我仍然在标题中看到 100 continue 愚蠢的 apache 仍然抱怨 505 错误 string url http
  • 按成员序列化

    我已经实现了template
  • 查找c中结构元素的偏移量

    struct a struct b int i float j x struct c int k float l y z 谁能解释一下如何找到偏移量int k这样我们就可以找到地址int i Use offsetof 找到从开始处的偏移量z
  • 使用实体框架模型输入安全密钥

    这是我今天的完美想法 Entity Framework 中的强类型 ID 动机 比较 ModelTypeA ID 和 ModelTypeB ID 总是 至少几乎 错误 为什么编译时不处理它 如果您使用每个请求示例 DbContext 那么很
  • BitTorrent 追踪器宣布问题

    我花了一点业余时间编写 BitTorrent 客户端 主要是出于好奇 但部分是出于提高我的 C 技能的愿望 我一直在使用理论维基 http wiki theory org BitTorrentSpecification作为我的向导 我已经建
  • 在 Windows 窗体中保存带有 Alpha 通道的单色位图会保存不同(错误)的颜色

    在 C NET 2 0 Windows 窗体 Visual Studio Express 2010 中 我保存由相同颜色组成的图像 Bitmap bitmap new Bitmap width height PixelFormat Form
  • C# 中通过 Process.Kill() 终止的进程的退出代码

    如果在我的 C 应用程序中 我正在创建一个可以正常终止或开始行为异常的子进程 在这种情况下 我通过调用 Process Kill 来终止它 但是 我想知道该进程是否已退出通常情况下 我知道我可以获得终止进程的错误代码 但是正常的退出代码是什
  • 使用 WebClient 时出现 System.Net.WebException:无法创建 SSL/TLS 安全通道

    当我执行以下代码时 System Net ServicePointManager ServerCertificateValidationCallback sender certificate chain errors gt return t
  • C#中如何移动PictureBox?

    我已经使用此代码来移动图片框pictureBox MouseMove event pictureBox Location new System Drawing Point e Location 但是当我尝试执行时 图片框闪烁并且无法识别确切
  • 转发声明和包含

    在使用库时 无论是我自己的还是外部的 都有很多带有前向声明的类 根据情况 相同的类也包含在内 当我使用某个类时 我需要知道该类使用的某些对象是前向声明的还是 include d 原因是我想知道是否应该包含两个标题还是只包含一个标题 现在我知
  • 如何在 C 中调用采用匿名结构的函数?

    如何在 C 中调用采用匿名结构的函数 比如这个函数 void func struct int x p printf i n p x 当提供原型的函数声明在范围内时 调用该函数的参数必须具有与原型中声明的类型兼容的类型 其中 兼容 具有标准定
  • 如何序列化/反序列化自定义数据集

    我有一个 winforms 应用程序 它使用强类型的自定义数据集来保存数据进行处理 它由数据库中的数据填充 我有一个用户控件 它接受任何自定义数据集并在数据网格中显示内容 这用于测试和调试 为了使控件可重用 我将自定义数据集视为普通的 Sy
  • Windows 窗体:如果文本太长,请添加新行到标签

    我正在使用 C 有时 从网络服务返回的文本 我在标签中显示 太长 并且会在表单边缘被截断 如果标签不适合表单 是否有一种简单的方法可以在标签中添加换行符 Thanks 如果您将标签设置为autosize 它会随着您输入的任何文本自动增长 为
  • 链接器错误:已定义

    我尝试在 Microsoft Visual Studio 2012 中编译我的 Visual C 项目 使用 MFC 但出现以下错误 error LNK2005 void cdecl operator new unsigned int 2
  • WPF/C# 将自定义对象列表数据绑定到列表框?

    我在将自定义对象列表的数据绑定到ListBox in WPF 这是自定义对象 public class FileItem public string Name get set public string Path get set 这是列表
  • 向现有 TCP 和 UDP 代码添加 SSL 支持?

    这是我的问题 现在我有一个 Linux 服务器应用程序 使用 C gcc 编写 它与 Windows C 客户端应用程序 Visual Studio 9 Qt 4 5 进行通信 是什么very在不完全破坏现有协议的情况下向双方添加 SSL
  • 如何在Xamarin中删除ViewTreeObserver?

    假设我需要获取并设置视图的高度 在 Android 中 众所周知 只有在绘制视图之后才能获取视图高度 如果您使用 Java 有很多答案 最著名的方法之一如下 取自这个答案 https stackoverflow com a 24035591
  • 基于 OpenCV 边缘的物体检测 C++

    我有一个应用程序 我必须检测场景中某些项目的存在 这些项目可以旋转并稍微缩放 更大或更小 我尝试过使用关键点检测器 但它们不够快且不够准确 因此 我决定首先使用 Canny 或更快的边缘检测算法 检测模板和搜索区域中的边缘 然后匹配边缘以查
  • 是否可以在 .NET Core 中将 gRPC 与 HTTP/1.1 结合使用?

    我有两个网络服务 gRPC 客户端和 gRPC 服务器 服务器是用 NET Core编写的 然而 客户端是托管在 IIS 8 5 上的 NET Framework 4 7 2 Web 应用程序 所以它只支持HTTP 1 1 https le

随机推荐

  • 以人为本

    软件团队想要保证高质量的软件交付 一般情况下会想到以下几点 多的测试人员 高薪资 福利 各种质量管理工具和手法 etc 我们有大量的实际经验表明 这些方法往往没有达到预期值 更有甚者 会不那么有效 为何会如此 通过不断的事后回顾 我想导致这
  • Kubernetes核心概念—工作负载

    Kubernetes的工作负载包括五种类型 Deployments 一个 Deployment 控制器为 Pods 和 ReplicaSets 提供声明式的更新能 StatefulSets StatefulSet 是用来管理有状态应用的工作
  • 行为型模式-解释器模式

    package per mjn pattern interpreter import java util HashMap import java util Map 环境角色类 public class Context 定义一个map集合 用
  • C++ 多态

    多态按字面的意思就是多种形态 当类之间存在层次结构 并且类之间是通过继承关联时 就会用到多态 C 多态意味着调用成员函数时 会根据调用函数的对象的类型来执行不同的函数 下面的实例中 基类 Shape 被派生为两个类 如下所示 实例 incl
  • 入行软件测试7年,才知道原来字节跳动这么容易进

    当前就业环境 裁员 失业消息满天飞 好像有一份工作就不错了 更别说高薪了 其实这只是一方面 而另一方面 各大企业依然求贤若渴 高技术人才依然紧缺 只要你技术过硬 拿个年薪50w不是问题 我的人生格言 比你优秀的人不可怕 可怕的是比你优秀的人
  • C# Winform基本知识、文件结构、控件简介

    1 程序入口 Program类 STAThread com线程模型 单线程单位 如果没有它 无法工作 Application 提供了一系列静态化方法和属性 来管理应用程序 Application EnableVisualStyles 启用应
  • Python 异常捕获与处理

    视频版教程 Python3零基础7天入门实战视频教程 异常捕获与处理 如果出现程序异常 我们不去捕获和处理 那么程序遇到异常 就直接终止 后续的代码无法继续执行 这将是可怕的事情 Python提供了完善的异常处理机制 可以实现捕获异常 处理
  • html头部代码

    学习html是件比较容易的事情 但单单学html语言肯定是不够用的 所以大多数人并没有拿html作为学习核心 而是将html作为javascript 动态语言或者css学习的必经之路 于是很多人并不关注一些其他的html标签 主流书籍大多对
  • 【JavaSE系列】第八话 —— 继承和它的边角料们

    导航小助手 思维导图 一 引出继承 二 继承的概念 三 继承的语法 四 父类成员访问 4 1 子类中访问父类的成员变量 4 2 子类访问父类的成员方法 五 super 关键字 5 1 super 成员变量 5 2 super 成员方法 5
  • QT学习 -- 12信号连接信号

    视频学习链接 https www bilibili com video BV1g4411H78N p 12 信号可以连接事件 普通函数 可以连接槽函数 也可以连接信号 一 信号触发 连接 信号 举例如下 当用鼠标点击按键 按键发出点击 cl
  • 【Leetcode】560. 和为K的子数组

    题目描述 给你一个整数数组 nums 和一个整数 k 请你统计并返回该数组中和为 k 的连续子数组的个数 题解 暴力解法 双循环 i指针从左往右走 j指针从i往左走 一个个遍历一个个加起来 直到加到等于k 就计数一次 执行用时 1445 m
  • okhttp异常: java.io.IOException: closed okio.RealBufferedSource$1.read

    java io IOException closed at okio RealBufferedSource 1 read RealBufferedSource java 405 at sun nio cs StreamDecoder rea
  • Redis——redis配置与优化

    文章目录 一 关系数据库与非关系型数据库 1 关系型数据库 2 非关系型数据库 二 Redis 简介 1 Redis的应用场景 2 Redis的优点 三 Redis 安装部署 1 安装Redis 2 配置参数 四 Redis
  • 任务管理器详解

    进程 看是否有除系统外多余进程 可能是病毒或没有完全关闭的进程 影响机器性能 进程下显示了所有当前正在运行的进程 包括应用程序 后台服务等 性能下可以看到CPU和内存 页面文件的使用情况 卡机 死机 中毒时 CPU使用率会达到100 CPU
  • mysql 用sqlyog连接1045错误解决办法(数据库在linux)

    1045 多半就是要么你端口号3306没开 要么就是你密码错误 安装网路分析 yum install net tools 防火墙开放3306端口 root localhost firewall cmd zone public add por
  • 学生信息管理系统(登录功能)

    工具eclipse 主要操作登陆 增删查改 编写实体类 public class Student private int id private String sId 学号 private String name private String
  • CTF BugKu平台———(Web篇②)

    源代码 unescape编码 https tool chinaz com Tools Escape aspx PS p1 35 34 61 61 32 p2 然后提交即可 67d709b2b54aa2aa648cf6e87a7114f1 文
  • 操作系统 线程同步实验

    操作系统 线程同步实验 一 实验目标 顺序表循环队列实现的实验目标 掌握使用顺序表和循环队列实现队列的基本操作 如队列的插入 删除 遍历等 同时了解循环队列的内部实现原理和利用循环队列解决实际问题的方法 Linux生产者 消费者问题的多线程
  • MFC自定义消息

    一 背景 消息机制是windows程序的典型运行机制 在MFC中有很多已经封装好了的消息 但是在有些特殊情况下我们需要自定义一些消息去完成一些我们所需要的功能 这时候MFC的向导不能帮助我们做到这一点 对此 我们可以通过添加相应的代码去完成
  • C++ 深浅拷贝、写时拷贝

    前言 本章以string类为例介绍浅拷贝与深拷贝 引用计数写时拷贝作为了解内容 string类的模拟实现参考C string类的模拟实现 文章目录 1 浅拷贝 2 深拷贝 3 引用计数 写时拷贝 1 浅拷贝 浅拷贝 对于有申请空间的对象的类