当前位置: 首页 > news >正文

C++之深浅拷贝

一、浅拷贝

我们看下以下代码
Test.h 文件

#pragma once
#include<iostream>
using namespace std;
class Student
{
public:Student(){}~Student(){if (m_Id != nullptr){delete m_Id;m_Id = nullptr;}}Student(int id, string strName){m_Id = new int[id];m_strName = strName;}
private:int* m_Id;string m_strName;
};

Test.cpp 文件

#include"Test.h"
int main()
{Student s1(1, "zhangsan");Student s2(s1);cout << "helloworld" << endl;return 0;
}

运行:
在这里插入图片描述
只是简单的构造了两个类对象,最后运行却崩溃了
崩溃点是析构函数

	~Student(){if (m_Id != nullptr){delete m_Id;m_Id = nullptr;}}

那么我们把这段删除掉试一试
在这里插入图片描述
运行:
在这里插入图片描述
ok 问题解决了?这样只会造成内存泄漏,并不是不释放 = 解决问题
但是这不是问题的本质
直接原因:析构函数,多次释放同一块空间,导致崩溃
根本原因:默认拷贝构造函数
是的,类的默认拷贝构造函数

	Student s1(1, "zhangsan");Student s2(s1);

在类 Student 中 并没有定义拷贝构造函数,那么在 Student s2(s1); 时会调用类的默认成员函数:拷贝构造函数
而浅拷贝会导致一个结果

s1->m_Id
s2->m_Id

这两个类对象的成员变量 m_Id 的地址其实是一致的
打印各自的m_Id

	void GetMemberAdd(){cout << m_Id << endl;}
	s1.GetMemberAdd();s2.GetMemberAdd();

结果:
在这里插入图片描述
那么两个类对象调用析构函数,s1 先析构 delete m_Id 接着 s2 再次释放,那么就属于非法操作一块空间,最终导致崩溃。

有些朋友,可能说并没有出现这种情况,是的如果只是值拷贝,不涉及,指针拷贝,引用时深浅拷贝是一样的。
那么当涉及到指针、引用时则需要自己实现拷贝构造函数,实现深拷贝,避免造浅拷贝所出现的问题。
并且建议最好自己实现一下拷贝构造函数与类对象的 “=” 操作符重载
否则也是会出现以下情况
在这里插入图片描述

二、深拷贝

看了上述的问题,那么如何来解决浅拷贝的问题呢,这里就引入深拷贝的问题
我们直到出现问题的原因是:

s1->m_Id Address == s2->m_Id Address

那么我们在拷贝构造函数为每一个新的类对象的都动态创建一个新的 m_Id 那么就可以解决浅拷贝的问题了,看代码

	Student(const Student& s){int iTemp = *(s.m_Id);m_Id = new int(iTemp);//动态申请新的空间,再赋值m_strName = s.m_strName;}

在这里插入图片描述
总结:深拷贝是开辟新的空间,再存储值,使用默认的拷贝构造,会将两个指针指向同一块空间(并没有开辟新的空间) 而是共用一块空间,因此在释放时会导致崩溃。

完整测试代码
Test.h

#pragma once
#include<iostream>
#include<string>
using namespace std;
class Student
{
public:Student(){}~Student(){if (m_Id != nullptr){delete m_Id;m_Id = nullptr;}}Student(int id, string strName){m_Id = new int(id);m_strName = strName;}Student(const Student& s){int iTemp = *(s.m_Id);m_Id = new int(iTemp);m_strName = s.m_strName;}void GetMemberAdd(){cout << m_Id << endl;}void Print(){cout << *m_Id << endl;cout << m_strName << endl;}
private:int* m_Id;string m_strName;
};

Test.cpp

#include"Test.h"
int main()
{Student s1(1, "zhangsan");Student s2(s1);s1.Print();s2.Print();cout << "helloworld" << endl;s1.GetMemberAdd();s2.GetMemberAdd();return 0;
}

相关文章:

C++之深浅拷贝

一、浅拷贝 我们看下以下代码 Test.h 文件 #pragma once #include<iostream> using namespace std; class Student { public:Student(){}~Student(){if (m_Id ! nullptr){delete m_Id;m_Id nullptr;}}Student(int id, string strName){m_Id new int[id];m_strName s…...

CoreLocation的一切

Overview 概述 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pgnvehxf-1678717852996)(./blog_cover.png)] Core Location 提供的服务可以确定设备的地理位置、高度和方向&#xff0c;或者它相对于附近 iBeacon 设备的位置。 该框架使用设备上的所…...

HashMap原理

初始化 从HashMap 源码中我们可以发现&#xff0c;HashMap的初始化有一下四种方式 //HashMap默认的初始容量大小 16&#xff0c;容量必须是2的幂 static final int DEFAULT_INITIAL_CAPACITY 1 << 4; // HashMap最大容量 static final int MAXIMUM_CAPACITY 1 <&…...

STM32入门笔记(02):独立看门狗(IWDG)和窗户看门狗(WWDG)(SPL库函数版)

1.IWDG狗简介 除了始终控制器的RCC_CSR寄存器的父为标志位和备份区域中的寄存器以外&#xff0c;系统复位 将复位所有寄存器至它们的复位状态。 当发生以下任一事件时&#xff0c;产生一个系统复位&#xff1a; 1.NRST引脚上的 低 电平&#xff0c;即 外部复位&#xff1b;2…...

javaSE系列之方法与数组的使用

[TOC] javaSE系列之方法与数组的使用 方法的定义 方法类似于C语言中的"函数"。 方法的种类 这里方法分为有参方法也分为无参方法&#xff0c; 形参和实参是两个实体&#xff08;这里相当于函数的传值调用和传址调用&#xff09; 1.非静态方法&#xff1a;普通方法/…...

常用命令总结

将常用命令汇集于此&#xff0c;以便在忘记的时候查询&#xff0c;持续更新…… Git Local changes 添加名字&#xff1a; git config --global user.name "<你的名字>"添加邮件&#xff1a; git config --globa user.email "<你的邮箱>"…...

【Linux:程序地址空间--原来操作系统也喜欢画大饼】

目录 1 代码感受 2 进程地址空间 3 扩展 1 代码感受 在正式讲程序地址空间前我们先来看一段简单的代码来分析分析&#xff1a; 1 #include<iostream>2 #include<unistd.h>3 using namespace std;4 5 int g_val100;6 7 int main()8 {9 pid_t idfork();10 if(i…...

Python实现简单信号滤波实战

在有些项目中需要对信号进行滤波处理&#xff0c;尤其是在医疗的设备中如心跳、脉搏等设备的采样后进行处理。滤波的目的就是除去某些频率的信号如噪声。常见的包括有低通滤波、高通滤波、带通滤波。 低通滤波指的是去除高于某一阈值频率的信号&#xff1b;高通滤波去除低于某…...

Java(110):非对称加密RSA的使用(KeyPair生成密钥)

Java(110)&#xff1a;非对称加密RSA的使用(KeyPair生成密钥) RSA 算法是一种非对称加解密算法。服务方生成一对 RSA 密钥&#xff0c;即公钥 私钥&#xff0c;将公钥提供给调用方&#xff0c;调用方使用公钥对数据进行加密后&#xff0c;服务方根据私钥进行解密。 1、RSA生…...

(Mybatis 学习【1】)整合 Mybatis 开发流程

Mybatis 整合流程 ① 添加MyBatis的依赖 ② 创建数据库表 ③ 编写pojo实体类 ④ 编写映射文件UserMapper.xml ⑤ 编写核心文件mybatis-config.xml ⑥ 编写测试类** 编写 pojo 实体类 (设计相应的数据库&#xff09; Data AllArgsConstructor NoArgsConstructor public class…...

一文搞懂Kerberos

Kerberos一词来源于古希腊神话中的Cerberus——守护地狱之门的三头犬&#xff0c;Kerberos是为TCP/IP 网络设计的可信第三方鉴别协议&#xff0c;最初是在麻省理工学院(MIT)为Athena 项目而开发的。Kerberos服务起着可信仲裁者的作用&#xff0c;可提供安全的网络鉴别&#xff…...

Go爬虫学习笔记(三)

day3 ‍ 04&#xff5c;敏捷之道&#xff1a;大型Go项目的开发流程是怎样的&#xff1f; 瀑布模式 流程&#xff1a; 市场调研需求分析产品设计研发实现集成与测试项目交付与维护 适用场景&#xff1a; 需求在规划和设计阶段就已经确定了&#xff0c;而且在项目开发周期内&…...

CASTEP参数设置(2)

虚拟试验&#xff08;分子模拟&#xff09; 在表征材料以及材料的相关性质时&#xff0c;只要是采用已有的理论加以解释 但是通常来说&#xff0c;需要采用已有的理论来进行设计和探索&#xff0c;伴随着工业软件的发展&#xff0c;应当选用仿真技术来缩小探索范围 传统试验V…...

浅谈对Promise的理解以及在工作中的应用

浅谈对Promise的理解以及在工作中的应用Promise的概念背景知识JavaScript的同步和异步JavaScript事件循环回调函数进行异步操作解决方案&#xff1a;PromisePromise 在工作中的运用创建PromisePromise封装AJAXPromise链式操作Promise.all()Promise.race()async和await总结Promi…...

开源|快速入门和理解并模拟实现GPS户外机器人的定位与导航

户外机器人的定位导航相对于需要建图的场景来说&#xff0c;是比较简单容易实现的&#xff0c;因为可以借助第三方地图完成定位&#xff0c;并在第三方地图中完成路径规划和下发航点等操作&#xff0c;实现的难题在于如何控制机器人完成步行和转弯。 这些在不引进RTK高精度定位…...

Java多线程系列--synchronized的原理

原文网址&#xff1a;Java多线程系列--synchronized的原理_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Java的synchronized的原理。 反编译出字节码 Test.java public class Test {private static Object LOCK new Object();public static int main(String[] args) {synchro…...

QEMU启动ARM64 Linux内核

目录前言前置知识virt开发板ARM处理器家族简介安装qemu-system-aarch64安装交叉编译工具交叉编译ARM64 Linux内核交叉编译ARM64 Busybox使用busybox制作initramfs使用QEMU启动ARM64 Linux内核前言 本文介绍采用 qemu 模拟ARM-64bit开发板&#xff08;针对ARM-32bit的有另一篇文…...

Linux->进程程序替换

目录 前言&#xff1a; 1 程序替换原理 2 单进程替换 3 替换函数 3.1 函数使用 4 程序去替换自己的另一个程序操作方式 5 实现自己的shell 前言&#xff1a; 通过我们之前对于子进程的应用&#xff0c;我相信大家一定是能够想到创建子进程的目的之一就是为了代劳父进程执…...

最强分布式锁工具:Redisson

1 Redisson概述1.1 什么是Redisson&#xff1f;Redisson是一个在Redis的基础上实现的Java驻内存数据网格&#xff08;In-Memory Data Grid&#xff09;。它不仅提供了一系列的分布式的Java常用对象&#xff0c;还提供了许多分布式服务。其中包括(BitSet, Set, Multimap, Sorted…...

Java9-17新特性

Java9-17新特性 一、接口的私有方法 Java8版本接口增加了两类成员&#xff1a; 公共的默认方法公共的静态方法 Java9版本接口又新增了一类成员&#xff1a; 私有的方法 为什么JDK1.9要允许接口定义私有方法呢&#xff1f;因为我们说接口是规范&#xff0c;规范时需要公开…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

CSS设置元素的宽度根据其内容自动调整

width: fit-content 是 CSS 中的一个属性值&#xff0c;用于设置元素的宽度根据其内容自动调整&#xff0c;确保宽度刚好容纳内容而不会超出。 效果对比 默认情况&#xff08;width: auto&#xff09;&#xff1a; 块级元素&#xff08;如 <div>&#xff09;会占满父容器…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

GitHub 趋势日报 (2025年06月06日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...

Razor编程中@Html的方法使用大全

文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...