[C++]深复制与浅复制

news2024/11/16 22:55:07

深复制与浅复制

C++中,默认的复制构造函数只能实现浅复制。

浅复制指的是在对象复制前,只对对象中的数据成员进行简单的复制

大多数情况下"浅复制"已经能很好的工作了,但是当类的数据成员中有指针类型时,浅复制只会复制指针的值(地址),这样会导致两个成员指针指向同一块内存,从而带来数据安全方面的隐患,如需要分别用delete释放指针所指向的空间时就会出现问题。为了实现正确的复制,此时我们必须编写复制构造函数进行深复制。

深复制指的是当类的成员变量有指针类型时,复制对象时应该为指针变量重新分配一个新的内存空间,使该指针指向这个新的内存空间,避免浅复制中只复制指针的值,使两个指针指向同一块内存。

浅复制和深复制主要的区别就是复制指针时是否创建内存空间 ,如果没有创建内存只复制地址为浅复制,创建新内存并把值全部复制一份就是深复制。采用深复制的情况下,释放内存的时候就不会出现浅复制时重复释放同一内存的错误。
下面是对象采用浅复制的一个案例!

#include <iostream>
#include <string.h>
using namespace std;

class Cperson{
	private:
		int m_age;
		char *m_name;
	public:
		Cperson(int age,char *name);
		~Cperson();
		void Print(void); 
};
Cperson::Cperson(int age,char *name){
	m_name = new char[strlen(name)+1];
	if(m_name!=NULL){
		strcpy(m_name,name);
	}
	m_age = age;
	cout<<m_age<<"的构造函数"<<endl;
}
Cperson::~Cperson(){
	cout<<"析构姓名:"<<m_name<<endl;
	if(m_name!=NULL){
		delete []m_name;	
	}
}
void Cperson::Print(void){
	cout<<"My age is "<<m_age<<",My name is "<<m_name<<endl;
}
int main(void)
{
	Cperson Tom(10,"Tom");
	Tom.Print();
	Cperson Jim(Tom);
	Jim.Print();
	
	return 0;
}

运行结果如下:
20230121_1
程序运行的结果出现了错误。这是因为在执行语句

CPerson Tom(10,"TOM");

用动态开辟了一块内存,用来存放"Tom"。而在执行

Cperson Jim(Tom);

时,调用的是默认构造复制函数,实现对应数据的直接复制,即将Tom的成员(Tom.m_age,Tom.m_name)赋值给Jim相应的成员。此时,Tom.m_nameJim.m_name 指向同一块内存,然而系统并没有给 Jim.m_name 开辟相应的内存空间。执行完 Jim.Print()之后,开始执行析构函数,析构函数的执行顺序和对象构造函数的执行顺序相反,所以先执行Jim的析构函数,执行完Jim的析构函数之后,Jim.m_name 所指向的空间已经释放。接着执行Tom的析构函数,此时就会出现问题,即在释放Tom.m_name 所指向的内存空间时会出现问题,因为这段内存空间在Jim的析构函数里已经释放过了。出现这种问题的根本原因在于默认复制构造函数实现的是"浅复制",所以需要定义自己的复制构造函数实现"深复制" ,就可以避免上述问题。下面的代码进行深复制的展示:

/*对象的深复制*/
#include <iostream>
#include <string.h>
using namespace std;

class Cperson{
	private:
		int m_age;
		char *m_name;
	public:
		Cperson(int age,char *name);
		Cperson(Cperson &per);
		~Cperson();
		void Print(void); 
};
Cperson::Cperson(int age,char *name){
	m_name = new char[strlen(name)+1];
	if(m_name!=NULL){
		strcpy(m_name,name);
	}
	m_age = age;
	cout<<m_name<<"的构造函数"<<endl;
}
Cperson::Cperson(Cperson &per){
	m_name = new char[strlen(per.m_name)+1];
	if(m_name != NULL){
		strcpy(m_name,per.m_name);
	}
	m_age = per.m_age;
	cout<<m_name<<"的拷贝构造函数"<<endl;
}

Cperson::~Cperson(){
	cout<<"析构姓名:"<<m_name<<endl;
	if(m_name!=NULL){
		delete []m_name;	
	}
}
void Cperson::Print(void){
	cout<<"My age is "<<m_age<<",My name is "<<m_name<<endl;
}
int main(void)
{
	Cperson Tom(10,"Tom");
	Tom.Print();
	Cperson Jim(Tom);
	Jim.Print();
	
	return 0;
}

运行结果如下:
20230121_2

总结:
不知道大家看完之后是否已经理解,其实浅复制与深复制之间的关系除了是否为指针变量开辟新的空间之外,还有一个理解角度就是:浅复制无需手动添加拷贝构造函数,深复制需要手动添加拷贝构造函数。

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

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

相关文章

Gulp.Task 正解

gulp task 实现过程 今天从源码的角度分析下 gulp 中 task 的实现过程。多个 task 是如何执行&#xff1f;&#xff1f;&#xff1f; 等等 gulp 插件分布图 其实通过上述截图可以看到&#xff0c;其实整个 gulp 内部什么逻辑都没有&#xff0c;都是由一个一个插件组成的。上述的…

Java多线程案例之单例模式(饿汉,懒汉)

目录 一、饿汉模式 二、懒汉模式 前言&#xff1a;单例模式是校招中最常见的设计模式之一。下面我们来谈谈其中的两个模式&#xff1a;懒汉&#xff0c;饿汉。 何为设计模式&#xff1f; 设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多…

《Linux性能优化实战》学习笔记 Day04

06 | 锁&#xff1a;如何根据业务场景选择合适的锁&#xff1f; 原文摘抄 当你无法判断锁住的代码会执行多久时&#xff0c;应该首选互斥锁&#xff0c;互斥锁是一种独占锁。 如果你能确定被锁住的代码执行时间很短&#xff0c;就应该用自旋锁取代互斥锁。 对于 99% 的线程…

工信部电子标准院:龙蜥操作系统获评“优秀”

近日&#xff0c;工信部中国电子技术标准化研究院公布第二批通过开源项目成熟度评估的开源项目名单&#xff0c;龙蜥操作系统&#xff08;Anolis OS&#xff09;凭借在生态构建、技术创新、应用落地等方面的成熟能力与卓越表现&#xff0c;顺利通过评估并获得优秀贰级&#xff…

简单说说什么是真的懂一道题了

昨天写了Richard的2022年一年级入学小结后&#xff0c;后台有读者问我怎么算真的懂一个知识点了&#xff0c;今天来简单说两句&#xff0c;大家都知道&#xff0c;求123…n的和&#xff0c;高斯的幼年成名作。Richard同学在上中班的时候&#xff0c;我就给他科普过高大神的事迹…

2023牛客寒假算法基础集训营3 -- E-公平守望的灯塔(向量 简单几何)

题目如下&#xff1a; 示例1 输入 1 0 0 1输出 0 0说明 输出1 1也是可以的。 思路 or 题解&#xff1a; 我们可以迅速找到 CCC 有两个位置满足题意&#xff0c;但 CCC 的坐标不一定是整数&#xff0c;我们需要 checkcheckcheck MMM 是 ABABAB 的中点 我们可以求出来 AM→…

「栈和队列」简析

前言 前言&#xff1a;研究一个数据结构的时候&#xff0c;首先讲的是增删改查。 文章目录前言一、简介1. 结构2. 特点3. 存储二、栈1. 类比举例2. 操作3. 实现1&#xff09;顺序栈&#xff08;常用&#xff09;a. 核心b. 要素c. 入栈d. 出栈2&#xff09;链式栈三、队列1. 类比…

Spring的Aware接口讲解,内含几篇参考文章

Aware接口文章一、使用Aware与不使用Aware的效果二、ApplicationContext实例介绍Aware三、从Aware顶级接口实现自己的XXXAware一、使用Aware与不使用Aware的效果 参考文章&#xff1a;Spring中的aware接口 定义BeanNameAware接口 public interface BeanNameAware extends Aw…

树的应用举例——并查集和树状数组

并查集 并查集是利用森林来描述一些不相交的集合&#xff0c;并支持集合的合并操作和查询操作。 假设有n个元素&#xff0c;分为m个不相交集合&#xff0c;一个集合构成一棵树&#xff0c;同一棵树&#xff08;集合&#xff09;中的元素地位相等。例如下图的森林表示一个包含…

【Python】Numpy多项式详解

文章目录多项式简介构造函数与图像运算符重载常用方法多项式简介 Numpy.polynomial中封装了六种多项式类&#xff0c;除了常规的多项式a0a1x⋯anxna_0a_1x\cdotsa_nx^na0​a1​x⋯an​xn之外&#xff0c;还有五种在数学、物理中常用的正交多项式&#xff0c;例如Hermite多项式…

祝贺!2022 Rust中文社区线上Hackathon评审结果出炉!

完全超出预期&#xff08;的优秀&#xff01;&#xff09;&#xff01;这次黑客松共有9支队伍闯入最后的评审会。他们是&#xff1a;233bithttps://github.com/rustcc/hackathon2022/tree/master/233bitRust 实现的 合成材料计算器EvolutionLabhttps://github.com/rustcc/hacka…

来自AI浩的新年祝福

大家好&#xff0c;感谢大家这一年来的关注和支持&#xff0c;在新春即将到来之际&#xff0c;AI浩祝大家&#xff1a; 祝大家新的一年里生活能够像下面的兔子那样&#xff0c;多彩多姿&#xff01; 祝愿大家&#xff0c;快乐常伴&#xff0c;笑口常开&#xff01; 在新的…

chfs安装使用注意事项及如何实现http外网访问

对于分享电脑上的文件&#xff0c;或与手机互传文件&#xff0c;除了 QQ、微信还有很多专业的工具&#xff0c;Cute Http File Server (缩写为 chfs)&#xff0c;就是一个免费小巧的 HTTP 文件共享服务器工具&#xff0c;它可以跨平台支持 Windows、Mac 和 Linux&#xff0c;只…

37岁被裁,但毫无遗憾:小镇出身,一穷二白,完整吃过互联网+房地产红利,现在上海有千万房产!...

有人被裁是失业&#xff0c;有人被裁是退休&#xff0c;有时候人类的悲欢真的不相通&#xff0c;来看看这位网友的故事&#xff1a;37岁&#xff0c;年底被裁&#xff0c;但是不留遗憾了。算是完整吃过一波互联网房地产红利&#xff0c;小镇出身&#xff0c;一穷二白&#xff0…

蚂蚁整改,暗藏深意

‍数据智能产业创新服务媒体——聚焦数智 改变商业互联网金融可以提升金融服务的效率和质量&#xff0c;促进传统产业转型升级&#xff0c;是资本竞相追逐的丛林&#xff0c;也是互联网巨头间相互争抢的战略高地。通过上市公司分拆子公司进行上市&#xff0c;可以获得一系列好…

C语言结构体 笔记

C语言提供结构体来管理不同类型的数据组合。C语言中的结构体类似于Java中的类。声明结构体类型定义变量名定义变量名和初始化结构体对齐结构体的大小必须是其最大成员的整数倍!&#xff08;1&#xff09;例如&#xff0c;此结构体的大小为16。因为double类型占8个字节&#xff…

聊一聊用户增长

#01 什么是用户增长 用户增长基本上会涉及生意场上的各行各业&#xff0c;你开个店面希望有更多的客户光顾&#xff0c;你做了个APP希望有更多的用户经常使用&#xff0c;你搭建了个电商平台希望有更多的人下单买东西。 用户增长&#xff0c;即以提升用户LTV为目的&#xff08…

MongoDB学习笔记【part1】概念与安装

一、NoSQL简介 NoSQL Not Only SQL&#xff0c;不仅仅是SQL&#xff0c;泛指非关系型数据库。NoSQL 不依赖业务逻辑方式存储&#xff0c;而以简单的key-value模式存储。因此大大的增加了数据库的扩展能力。 特点&#xff1a;不遵循SQL标准、不支持ACID&#xff08;原子、一致…

Linux常用命令——sysctl命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) sysctl 时动态地修改内核的运行参数 补充说明 sysctl命令被用于在内核运行时动态地修改内核的运行参数&#xff0c;可用的内核参数在目录/proc/sys中。它包含一些TCP/ip堆栈和虚拟内存系统的高级选项&#xff…

FANUC机器人INTP-250或251用户坐标系或工具坐标系与示教资料不符报警的处理办法

FANUC机器人INTP-250或251用户坐标系或工具坐标系与示教资料不符报警的处理办法 在机器人的日常使用过程中,有可能会碰到这样的情况: 点位的示教是在工具坐标系1、用户坐标系0下示教的,如下图所示, 但是使用过程中可能被自己或别人不小心修改成了工具坐标系2、用户坐标系…