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 提供的服务可以确定设备的地理位置、高度和方向,或者它相对于附近 iBeacon 设备的位置。 该框架使用设备上的所…...
HashMap原理
初始化 从HashMap 源码中我们可以发现,HashMap的初始化有一下四种方式 //HashMap默认的初始容量大小 16,容量必须是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寄存器的父为标志位和备份区域中的寄存器以外,系统复位 将复位所有寄存器至它们的复位状态。 当发生以下任一事件时,产生一个系统复位: 1.NRST引脚上的 低 电平,即 外部复位;2…...

javaSE系列之方法与数组的使用
[TOC] javaSE系列之方法与数组的使用 方法的定义 方法类似于C语言中的"函数"。 方法的种类 这里方法分为有参方法也分为无参方法, 形参和实参是两个实体(这里相当于函数的传值调用和传址调用) 1.非静态方法:普通方法/…...
常用命令总结
将常用命令汇集于此,以便在忘记的时候查询,持续更新…… Git Local changes 添加名字: git config --global user.name "<你的名字>"添加邮件: git config --globa user.email "<你的邮箱>"…...

【Linux:程序地址空间--原来操作系统也喜欢画大饼】
目录 1 代码感受 2 进程地址空间 3 扩展 1 代码感受 在正式讲程序地址空间前我们先来看一段简单的代码来分析分析: 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实现简单信号滤波实战
在有些项目中需要对信号进行滤波处理,尤其是在医疗的设备中如心跳、脉搏等设备的采样后进行处理。滤波的目的就是除去某些频率的信号如噪声。常见的包括有低通滤波、高通滤波、带通滤波。 低通滤波指的是去除高于某一阈值频率的信号;高通滤波去除低于某…...

Java(110):非对称加密RSA的使用(KeyPair生成密钥)
Java(110):非对称加密RSA的使用(KeyPair生成密钥) RSA 算法是一种非对称加解密算法。服务方生成一对 RSA 密钥,即公钥 私钥,将公钥提供给调用方,调用方使用公钥对数据进行加密后,服务方根据私钥进行解密。 1、RSA生…...
(Mybatis 学习【1】)整合 Mybatis 开发流程
Mybatis 整合流程 ① 添加MyBatis的依赖 ② 创建数据库表 ③ 编写pojo实体类 ④ 编写映射文件UserMapper.xml ⑤ 编写核心文件mybatis-config.xml ⑥ 编写测试类** 编写 pojo 实体类 (设计相应的数据库) Data AllArgsConstructor NoArgsConstructor public class…...

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

Go爬虫学习笔记(三)
day3 04|敏捷之道:大型Go项目的开发流程是怎样的? 瀑布模式 流程: 市场调研需求分析产品设计研发实现集成与测试项目交付与维护 适用场景: 需求在规划和设计阶段就已经确定了,而且在项目开发周期内&…...

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

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

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

Java多线程系列--synchronized的原理
原文网址: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开发板(针对ARM-32bit的有另一篇文…...

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

最强分布式锁工具:Redisson
1 Redisson概述1.1 什么是Redisson?Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。其中包括(BitSet, Set, Multimap, Sorted…...
Java9-17新特性
Java9-17新特性 一、接口的私有方法 Java8版本接口增加了两类成员: 公共的默认方法公共的静态方法 Java9版本接口又新增了一类成员: 私有的方法 为什么JDK1.9要允许接口定义私有方法呢?因为我们说接口是规范,规范时需要公开…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...

LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

嵌入式学习之系统编程(九)OSI模型、TCP/IP模型、UDP协议网络相关编程(6.3)
目录 一、网络编程--OSI模型 二、网络编程--TCP/IP模型 三、网络接口 四、UDP网络相关编程及主要函数 编辑编辑 UDP的特征 socke函数 bind函数 recvfrom函数(接收函数) sendto函数(发送函数) 五、网络编程之 UDP 用…...

轻量级Docker管理工具Docker Switchboard
简介 什么是 Docker Switchboard ? Docker Switchboard 是一个轻量级的 Web 应用程序,用于管理 Docker 容器。它提供了一个干净、用户友好的界面来启动、停止和监控主机上运行的容器,使其成为本地开发、家庭实验室或小型服务器设置的理想选择…...
CppCon 2015 学习:REFLECTION TECHNIQUES IN C++
关于 Reflection(反射) 这个概念,总结一下: Reflection(反射)是什么? 反射是对类型的自我检查能力(Introspection) 可以查看类的成员变量、成员函数等信息。反射允许枚…...
深入解析 ReentrantLock:原理、公平锁与非公平锁的较量
ReentrantLock 是 Java 中 java.util.concurrent.locks 包下的一个重要类,用于实现线程同步,支持可重入性,并且可以选择公平锁或非公平锁的实现方式。下面将详细介绍 ReentrantLock 的实现原理以及公平锁和非公平锁的区别。 ReentrantLock 实现原理 基本架构 ReentrantLo…...