类和对象-C++运算符重载-赋值运算符重载

赋值运算符重载

#include<bits/stdc++.h>
using namespace std;
//赋值运算符重载
class Person
{
public:
	Person(int age)
	{
		m_Age = new int(age);
	}
	~Person()
	{
		if(m_Age!=NULL)
		{
			delete m_Age;
			m_Age = NULL;	
		}	
	}
	
	//重载赋值运算符
	Person& operator=(Person &p) 
	{
		//应该先判断是否有属性在堆区,如果有先释放干净,然后再深拷贝
		if(m_Age !=NULL)
		{
			delete m_Age;
			m_Age=NULL;	
		}
		//深拷贝 
		m_Age=new int(*p.m_Age); 
		
		//返回对象本身
		return *this; 
	} 
	
	int *m_Age;	
};
void test01()
{
	Person p1(18);
	Person p2(20);
	Person p3(30); 
	p3 = p2 = p1;//赋值操作 
	cout<<"p1的年龄为:"<<*p1.m_Age<<endl;
	cout<<"p2的年龄为:"<<*p2.m_Age<<endl;
	cout<<"p3的年龄为:"<<*p3.m_Age<<endl;
}
int main(){
	test01();
	return 0;
}

为什么要运算符重载

  • 在赋值运算符重载(operator=)未定义的情况下,编译器会自动生成默认的浅拷贝赋值操作符。由于 Person 类中使用了动态分配的 int 类型成员 m_Age,这可能导致浅拷贝问题。

  • Person 类中,使用了动态分配内存来存储年龄 m_Age,并在析构函数中正确地释放了这块内存。然而,没有定义赋值运算符重载,这意味着默认的赋值操作符将会进行浅拷贝,即简单地复制指针而不是创建新的动态内存副本。

  • 如果使用默认的浅拷贝赋值操作符,那么当 p2 = p1; 执行时,p2.m_Age 将指向与 p1.m_Age 相同的内存地址。这样,当 p1p2 的析构函数调用时,会尝试删除同一个 int 对象,可能导致错误的行为,如双重释放内存(double free)。

  • 在 C++ 中,当类中存在动态分配的资源时,需要特别注意赋值运算符的重载,确保进行适当的资源管理,避免出现内存泄漏或双重释放的问题。
    在你的代码中,为什么需要实现析构函数 ~Person() 呢?让我们来详细解释一下:

为什么需要析构函数 ~Person()

  1. 动态内存管理:
  • Person 类中,使用了 new 运算符为 m_Age 动态分配了内存,这意味着 m_Age 指向的内存块是在堆区分配的。在类的生命周期内,如果不手动释放这块内存,它会一直存在,直到程序结束,这可能导致内存泄漏。
  • 析构函数 ~Person() 的作用是在对象被销毁时(比如对象的作用域结束、delete 对象、程序结束等),释放类成员变量 m_Age 指向的内存。这样可以确保在对象销毁时,相关的资源得到正确释放,避免内存泄漏。
  1. 避免悬空指针:
  • 如果不在析构函数中释放 m_Age,而是在对象销毁时直接结束,那么 m_Age 将成为悬空指针,即指向的内存被释放但指针本身未被置空。这会导致后续使用该指针访问内存时发生未定义行为,可能导致程序崩溃或数据损坏。

对于
if(m_Age !=NULL)
{
delete m_Age;
m_Age=NULL;
}
为什么要先判断是否有属性在堆区呢

在C++中,进行内存管理时,特别是对动态分配的资源(如指针所指向的内存)进行释放时,最好先进行空指针判断,然后再释放指针指向的内存。这种做法是为了避免出现悬空指针(dangling pointer)的问题。

具体来说,在赋值运算符重载函数中,先判断 m_Age 是否为 NULL(或 nullptr,C++11及以后的标准推荐使用 nullptr),是一种良好的习惯。如果不进行判断而直接调用 delete m_Age;,那么在以下情况可能会出现问题:

  1. 自我赋值问题: 如果你尝试将对象赋值给自己(例如 p1 = p1;),在没有判断的情况下直接 delete m_Age; 可能会导致 m_Age 被删除,而后续再访问 m_Age 就会出现未定义行为(UB)或崩溃。

  2. 多次赋值问题: 如果一个对象多次被赋值,而在每次赋值前没有释放之前分配的内存,就会造成内存泄漏。每次赋值前先释放资源可以避免这种情况。

所以,在赋值运算符重载函数中,先判断并释放已有资源是为了确保资源被正确地管理和清理。这样可以有效地避免内存泄漏,并保证代码在各种情况下的健壮性和可靠性。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

昇思25天学习打卡营第19天|LSTM+CRF序列标注

概述 序列标注指给定输入序列&#xff0c;给序列中每个Token进行标注标签的过程。序列标注问题通常用于从文本中进行信息抽取&#xff0c;包括分词(Word Segmentation)、词性标注(Position Tagging)、命名实体识别(Named Entity Recognition, NER)等。 条件随机场&#xff08…

01:spring

文章目录 一&#xff1a;常见面试题1&#xff1a;什么是Spring框架&#xff1f;1.1&#xff1a;spring官网中文1.2&#xff1a;spring官网英文 2&#xff1a;谈谈自己对于Spring IOC和AOP的理解2.1&#xff1a;IOCSpring Bean 的生命周期主要包括以下步骤&#xff1a; 2.2&…

国产化新标杆:TiDB 助力广发银行新一代总账系统投产上线

随着全球金融市场的快速发展和数字化转型的深入推进&#xff0c;金融科技已成为推动银行业创新的核心力量。特别是在当前复杂多变的经济环境下&#xff0c;银行业务的高效运作和风险管理能力显得尤为重要。总账系统作为银行会计信息系统的核心&#xff0c;承载着记录、处理和汇…

MySQL-行级锁(行锁、间隙锁、临键锁)

文章目录 1、介绍2、查看意向锁及行锁的加锁情况3、行锁的演示3.1、普通的select语句&#xff0c;执行时&#xff0c;不会加锁3.2、select * from stu where id 1 lock in share mode;3.3、共享锁与共享锁之间兼容。3.4、共享锁与排他锁之间互斥。3.5、排它锁与排他锁之间互斥3…

离线开发(VSCode、Chrome、Element)

一、VSCode 扩展 使用能联网的电脑 A&#xff0c;在VSCode官网下载安装包 使用能联网的电脑 A&#xff0c;从扩展下载vsix扩展文件 将VSCode安装包和vsix扩展文件通过手段&#xff08;u盘&#xff0c;刻盘 等&#xff09;导入到不能联网的离线电脑 B 中 在离线电脑 B 中安装…

计算机网络之无线局域网

1.无线局域网工作方式 工作方式&#xff1a;每台PC机上有一个无线收发机&#xff08;无线网卡&#xff09;&#xff0c; 它能够向网络上的其他PC机发送和接受无线电信号。 与有线以太网相似&#xff0c;无线局域网也是打包方式发送数据的。每块网卡都有一个永久的、唯一的ID号…

springboot配置扫描生效顺序

文章目录 举例分析项目结构如下noddles-user-backend 两个配置文件noddles-user-job 配置文件noddles-user-server 配置文件问题:server和Job启动时对应加载的数据库配置为哪一个&#xff1f; 总结 在微服务架构中&#xff0c;backend模块会定义一个基础的配置文件&#xff0c;…

java集合(2)

目录 一. Map接口下的实现类 1. HashMap 1.1 HashMap常用方法 2. TreeMap 2.1 TreeMap常用方法 3. Hashtable 3.1 Hashtable常用方法 4.Map集合的遍历 4.1 根据键找值 4.2 利用map中的entrySet()方法 二.Collections类 1.Collections类中的常用方法 三. 泛型 1. 为什…

运维锅总详解系统启动流程

本文详细介绍Linux及Windows系统启动流程&#xff0c;并分析了它们启动流程的异同以及造成这种异同的原因。希望本文对您理解系统的基本启动流程有所帮助&#xff01; 一、Linux系统启动流程 Linux 系统的启动流程可以分为几个主要阶段&#xff0c;从电源开启到用户登录。每个…

揭秘IP:从虚拟地址到现实世界的精准定位

1.IP地址介绍 1.内网 IP 地址&#xff08;私有 IP 地址&#xff09; 内网 IP 地址&#xff0c;即私有 IP 地址&#xff0c;是在局域网&#xff08;LAN&#xff09;内部使用的 IP 地址。这些地址不会在公共互联网中路由&#xff0c;因此可以在多个局域网中重复使用。私有 IP 地…

设计模式探索:责任链模式

1. 什么是责任链模式 责任链模式 (Chain of Responsibility Pattern) 是一种行为型设计模式。定义如下&#xff1a; 避免将一个请求的发送者与接收者耦合在一起&#xff0c;让多个对象都有机会处理请求。将接收请求的对象连接成一条链&#xff0c;并且沿着这条链传递请求&…

14-43 剑和诗人17 - ActiveRAG之主动学习

​​​​​ 大型语言模型 (LLM) 的出现开启了对话式 AI 的新时代。这些模型可以生成非常像人类的文本&#xff0c;并且比以往更好地进行对话。然而&#xff0c;它们在仅依赖预训练知识方面仍然面临限制。为了提高推理能力和准确性&#xff0c;LLM 需要能够整合外部知识。 检索…

文件存储的方法一

文章目录 概念介绍实现方法示例代码 我们在上一章回中介绍了"如何实现本地存储"相关的内容&#xff0c;本章回中将介绍如何实现文件存储.闲话休提&#xff0c;让我们一起Talk Flutter吧。 概念介绍 我们在上一章回中介绍的本地存储只能存储dart语言中基本类型的数值…

ffmpeg图片视频编辑器工具的安装与使用

title: ffmpeg图片视频编辑器工具的安装与使用 tags: [ffmpeg, 图片, 音频, 视频, 工具, 流媒体] categories: [工具, ffmpeg] FFmpeg是一个开源的命令行工具&#xff0c;广泛用于处理视频和音频文件&#xff0c;包括转换格式、剪辑、混流、解码、编码等。以下是一些基本的FFmp…

Zabbix 的部署和自定义监控内容

前言 一个完整的项目的业务架构包括 客户端 -> 防火墙 -> 负载均衡层&#xff08;四层、七层 LVS/HAProxy/nginx&#xff09; -> Web缓存/应用层&#xff08;nginx、tomcat&#xff09; -> 业务逻辑层(php/java动态应用服务) -> 数据缓存/持久层&#xff08;r…

智慧水利的变革之路:如何通过大数据、物联网和人工智能构建高效、智能、可持续的水利管理新模式

目录 一、引言&#xff1a;智慧水利的时代背景与意义 二、大数据&#xff1a;水利管理的数据基石 &#xff08;一&#xff09;数据收集与整合 &#xff08;二&#xff09;数据分析与挖掘 三、物联网&#xff1a;水利管理的感知神经 &#xff08;一&#xff09;智能感知与监…

Git 操作补充:cherry-pick、变基

1. 挑选提交合并 git cherry-pick 对于多分支的代码库&#xff0c;将代码从一个分支转移到另一个分支是一种常见的需求&#xff0c;这可以分成两种情况&#xff1a;一种情况是&#xff0c;你需要另一个分支的所有代码变动&#xff0c;那么就采用 git merge&#xff1b;另一种情…

【Unity2D 2022:UI】制作角色血条

一、创建血底UI 1. 创建画布&#xff08;Canvas&#xff09; 2. 在画布上添加血底图像&#xff08;Image&#xff09;子物体 二、编辑血底UI 1. 将血底图片拖入源图像&#xff08;Source Image&#xff09;中 2. 点击设置为图片的原大小&#xff08;Set Native Size&#x…

算法重新刷题

基础算法 前缀和 一维前缀和 [USACO16JAN] Subsequences Summing to Sevens S - 洛谷 这一题主要是需要结合数学知识来求解&#xff0c; #include <iostream> #include <cstring> #include <cstdio> #include <algorithm>using namespace std;con…

java花店管理系统eclipse开发mysql数据库

1 绪论 1.1 系统开发目的 随着人们物质生活水平和经济水平的不断提高&#xff0c;室内绿化布置、家庭园艺装饰、礼仪鲜花等日益受到重视和青睐&#xff0c;以及送鲜花给亲朋好友来表达自己的情谊。传统的花店对于信息的管理的主要方式是基于文本、表格等纸质手工处理&#xf…