C++学习笔记----8、掌握类与对象(一)---- 对象中的动态内存分配(2)

news2024/9/25 9:05:11

2.2、用析构函数释放内存

        每当完成动态分配内存时,都应该释放。如果在一个对象中动态分配内存,释放内存的地方就是析构函数。编译器保证当对象被破坏时会调用析构函数。下面就是Spreadsheet类定义中的析构函数:

export class Spreadsheet
{
public:
	Spreadsheet(std::size_t width, std::size_t height);
	~Spreadsheet();
    // Code omitted for brevity
};

        析构函数拥有与类(以及构造函数)同样的名字,前面加一个~。析构函数没有参数,只能有一个。析构函数不会抛出例外。

        下面是Spreadsheet类析构函数的实现:

Spreadsheet::~Spreadsheet()
{
	for (size_t i{ 0 }; i < m_width; ++i) {
		delete[] m_cells[i];
	}
	delete[] m_cells;
	m_cells = nullptr;
}

        析构函数释放在构造函数中分配的内存。然而,没有规则要求你在析构函数中释放内存。可以在析构函数中写任何想写的代码,但是将其用于释放内存或者其它资源通常是一个好主意。

2.3、处理拷贝与赋值

        如果你不写拷贝构造函数与拷贝赋值操作符,c++会为你写的。这些编译器生成的成员函数递归调用对象数据成员的拷贝构造函数或者拷贝赋值操作符。然而,对于原始类型,比如int,double,以及指针,它们提供了shallow或者说bitwise拷贝或者赋值:只是拷贝或者将数据成员从源对象直接赋值给目标对象。这避免了在对象动态分配内存时的总是。例如,下面的代码拷贝了spreadsheet s1,当s1被传递给printSpreadsheet()函数时初始化s:

import spreadsheet;

void printSpreadsheet(Spreadsheet s)
{
	// code omitted for brevity
}

int main()
{
	Spreadsheet s1{ 4, 3 };
	printSpreadsheet(s1);
}

        Spreadsheet包含一个指针变量:m_cells。Spreadsheet的一个shallow拷贝给出目标对象一个m_cells指针的拷贝,但不是其内部数据的拷贝。这样的话,结果就是s与s1具有指向同样数据的指针,如下图所示:

        如果s改变了m_cells指向的一些东东,其变化也会在s1中显现。更糟的是,当printSpreadsheet()函数退出时,s的析构函数被调用,就会释放m_cells指向的内存。就会造成s1中的m_cells不再指向有效的内存,如下图所示。这叫做悬浮指针。

        令人难以置信的是,这个问题在赋值时更加糟糕。假定有下面的代码:

		Spreadsheet s1{ 2, 2 }, s2{ 4, 3 };
		s1 = s2;

        执行完第一行代码后,s1与s2的Spreadsheet对象都会被构建,内存结构如下所示:

        当赋值语句执行完后,内存结构就变成下面的了:

        现在,不光s1与s2中的m_cells指针指向同样的内存,前面s1指向的m_cells的内存也变成了孤儿。这就叫做内存渗露了。

        需要明确的是,拷贝构造函数与拷贝赋值操作符必须做深层次的拷贝;也就是说,不光要拷贝指针数据成员,也要拷贝这些指针指向的真实数据。

        可以看出来,依靠c++缺省的拷贝构造函数与缺省的拷贝赋值操作符并不总是一个好主意。

        警告:每当在类中有动态分配资源时,应该自己写拷贝构造函数与拷贝赋值操作符来提供内存的深层次拷贝。

2.3.1、Spreadsheet拷贝构造函数

        下面是Spreadsheet类的拷贝构造函数的声明:

export class Spreadsheet
{
public:
    Spreadsheet(const Spreadsheet& src);
    // Code omitted for brevity
};

        定义如下:

Spreadsheet::Spreadsheet(const Spreadsheet& src)
	: Spreadsheet { src.m_width, src.m_height }
{
	// The ctor-initializer of this constructor delegates first to the
	// non-copy constructor to allocate the proper amount of memory.

	// The next step is to copy the data.
	for (size_t i{ 0 }; i < m_width; ++i) {
		for (size_t j{ 0 }; j < m_height; ++j) {
			m_cells[i][j] = src.m_cells[i][j];
		}
	}
}

        注意代理构造函数的使用。拷贝构造函数的构造函数初始化器首先代理非拷贝构造函数来分配适合大小的内存。拷贝构造函数体拷贝真实值。与之一起,该过程实现了m_cells动态分配二维数组的深层次拷贝。

        不需要删除任何既有的m_cells,因为这是一个拷贝构造函数,因此在this对象中还不存在m_cells。

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

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

相关文章

秋分之际,又搭建了一款微信记账本小程序

在这个金色的季节里&#xff0c;每一粒粮食都蕴含着生命的奇迹&#xff0c;每一片叶子都在诉说着成长的故事。秋分之际&#xff0c;又搭建了一款微信记账本小程序。 产品概述 微信记账本小程序是一款便捷的个人财务管理工具&#xff0c;旨在帮助用户轻松记录、管理和分析日常…

STM32基础学习笔记-NVIC中断面试基础题4

第四章、NVIC: 外部中断_串口中断 1、按键按下后&#xff0c;GPIO 会产生一个上升/下降沿&#xff0c;G030内部是如何触发外部中断的呢&#xff1f; 配置GPIO引脚&#xff1a; 首先&#xff0c;需要将特定的GPIO引脚配置为输入模式&#xff0c;并设置为外部中断源。这通常通过…

Nexus3的妙用

nexus 3使用场景 Nexus是一个全能仓库,通过部署nexus可以实现包含yum、apt、Maven、pypi、docker等的多种仓库。以下是nexus的适用场景: 当公共仓库无法访问或缓慢时,搭建nexus。比如国内docker无法访问,需要镜像加速。可以使用海外主机部署nexus,在nexus中创建docker(p…

uniapp微信小程序遮罩层u-popup禁止底层穿透

添加 touchmove.prevent&#xff0c;遮罩层底部的页面就不会滑动了微信开发者工具不生效&#xff0c;真机生效 <u-popup :show"showEwm" close"closeEwm" mode"center" touchmove.prevent><view class"ewmshow"></vie…

宝塔部署vue项目出现的各种问题

使用宝塔面板&#xff0c;网站页面&#xff0c;构建php静态网页 问题一&#xff1a;图片等静态资源无法加载 找到真正请求的url&#xff0c; 然后在项目目录下面创建对应的目录&#xff0c;将资源放入 问题二&#xff1a;刷新出现404 在这里任意位置添加 ## 添加上这个配…

力扣【118-杨辉三角】【数组-C语言】

题目&#xff1a;力扣-118 杨辉三角&#xff1a;&#xff08;算法思路&#xff09; 1. 每行第一个数和最后一个数都是1 2. 把杨辉三角左端对齐&#xff0c;从第三行开始&#xff0c;非首尾的元素值等于上一行同列的元素与该元素之前的元素之和&#xff0c;即 t [ j ] r e t …

软考高级:需求工程- 需求获取方式 AI解读

需求获取是项目管理和产品开发中的关键步骤&#xff0c;关系到项目的成功与否。你提到的几种需求获取方式涵盖了多个维度&#xff0c;以下我将逐一解析它们的用途与优势。 生活化例子 需求获取就像你要准备一场家庭聚会&#xff0c;需要先了解每个家庭成员的喜好。你可以通过…

【OceanBase 诊断调优】—— GC问题根因分析

GC 流程涉及到 RS 的状态切换和 LS 的资源安全回收&#xff0c;流程上较长。且 GC 线程每个租户仅有一个&#xff0c;某个日志流 GC Hang 死时会卡住所有其余日志流的 GC&#xff0c;进而造成更大的影响。 本文档会帮助大家快速定位到 GC 故障的模块&#xff0c;直达问题核心。…

SQL分组聚合子查询问题

场景 订单表 t_order 有如下数据&#xff1a; 字段分别为&#xff0c; 销售订单号、 订货数量 发货表 t_order_delivery 有如下数据&#xff1a; 字段分别为&#xff0c; 销售订单号、 发货数量 问题 问题1&#xff1a;查询部分发货的 销售订单号数据 &#xff1f; 分析…

数据集-目标检测系列-海洋鱼类检测数据集 fish>> DataBall

数据集-目标检测系列-海洋鱼类检测数据集 fish>> DataBall 数据集-目标检测系列-海洋鱼类检测数据集 fish 数据量&#xff1a;1W 数据项目地址&#xff1a; gitcode: https://gitcode.com/DataBall/DataBall-detections-100s/overview github: https://github.com/…

wpf中如何访问控件和生成使用事件?

实际上对于初次使用wpf的同学来说&#xff0c;尤其是有winform编程经验的童鞋来说&#xff0c;最需要解决的就是快速掌握访问控件的方法以及生成和使用事件。这样才能让页面具有最起码的交互性。下面我们来分别讲述。 文章原出处&#xff1a;https://blog.csdn.net/haigear/ar…

「数组」离散化 / Luogu B3694(C++)

目录 概述 思路 算法过程 复杂度 Code 概述 Luogu B3694&#xff1a; 给定一个长度为 n 的数列 aa。定义 rank(i) 表示数列 a 中比 ai 小的不同数字个数再加一。 对 1≤i≤n&#xff0c;现在请你求出所有的 rank(i)。 输出格式 对每组数据&#xff0c;输出一行 n 个整数&a…

智慧照明,安全度夏:揭秘如何前置防御暴雨中的路灯杆漏电隐患

随着夏季暴雨频发&#xff0c;多地近期发生的多起路人因路灯杆漏电触电身亡的悲剧&#xff0c;再次为公众安全敲响了警钟。从河南郑州到辽宁营口&#xff0c;一起起触目惊心的触电事故&#xff0c;不仅夺走了宝贵的生命&#xff0c;也引发了社会各界对暴雨天气下公共设施安全隐…

轴承介绍以及使用

轴承&#xff08;Bearing&#xff09;是在机械传动过程中起固定、旋转和减小载荷摩擦系数的部件。也可以说&#xff0c;当其它机件在轴上彼此产生相对运动时&#xff0c;用来降低运动力传递过程中的摩擦系数和保持转轴中心位置固定的机件。 轴承是当代机械设备中一种举足轻重的…

Go Mail设置指南:如何提升发送邮件效率?

Go Mail使用技巧与配置教程&#xff1f;如何用Go Mail实现发信&#xff1f; 随着工作负载的增加&#xff0c;如何高效地发送和管理邮件成为了许多职场人士面临的挑战。AokSend将为您提供一份详细的Go Mail设置指南&#xff0c;帮助您提升发送邮件的效率&#xff0c;让您的邮件…

数据库学习1

&#x1f31f;欢迎来到 我的博客 —— 探索技术的无限可能&#xff01; &#x1f31f;博客的简介&#xff08;文章目录&#xff09; 目录 登录 查看所有库 切换数据库 查看对应库所有的表 修改权限和密码 启动和停止服务器 创建数据库 查看数据库的表结构 创建表 在表…

Github Webhook触发Jenkins自动构建

1.功能说明 Github Webhook可以触发Jenkins自动构建&#xff0c;通过配置Github Webhook&#xff0c;每次代码变更之后&#xff08;例如push操作&#xff09;&#xff0c;Webhook会自动通知Jenkins服务器&#xff0c;Jenkins会自动执行预定义的构建任务&#xff08;如Jenkins …

揭秘“隐形杀手”:谐波对医院电网的隐形危害

谐波主要由非线性负载设备如医疗器械、节能照明、变频调速装置等产生。在医院的复杂配电网络中&#xff0c;这些谐波成分如同细小的波纹&#xff0c;不断叠加&#xff0c;最终扰乱了电能的纯净性&#xff0c;导致电能品质下降&#xff0c;电力供应的可靠性也随之降低。 医院里…

Linux ping c实现

linux下ping程序的c实现 #include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdint.h> #include <netdb.h> #include <arpa/inet.h> #include <unistd.h> #include <st…

服务设计原则介绍

在Java或任何软件开发中&#xff0c;设计服务时遵循一些核心原则是非常重要的&#xff0c;这些原则不仅有助于构建高质量、可维护的软件系统&#xff0c;还能提高系统的可扩展性和可重用性。以下是一些关键的服务设计原则&#xff1a; 单一职责原则&#xff08;SingleResponsib…