C++ 动态内存分配

news2024/9/28 7:20:45

在C++中动态内存的分配技术可以保证程序在允许过程中按照实际需要申请适量的内存,使用结束后还可以释放,这种在程序运行过程中申请和释放的存储单元也称为堆。 申请和释放过程一般称为建立和删除。

在C++程序中,建立和删除堆对象使用两个运算符:new和delete。

1.运算符new的功能是动态分配内存,或者称为动态创建堆对象,语法形式为:

new 数据类型(初始化列表参数);

该语句在程序运行过程中申请分配用于存放指定类型数据的内存空间,并根据初始化参数列表中给出的值进行初始化。如果内存申请成功,new运算符便返回一个指向新分配内存首地址的类型的指针,可以通过这个指针对该内存空间进行访;如果申请失败,会抛出异常。

(1)对于基本类型的对象

如果建立的对象是一个基本类型的变量,初始化过程就是赋值,例如:

int *p;
p=new int(2);

动态分配了用于存放int型数据的内存空间,并将初值2存入该空间中,然后将首地址赋给指针p。

【注意】对于基本数据类型,如果不希望在内存分配后设定初值,可以把括号省去,例如:

int *p=new int;

如果保留括号,但括号中不写任何数值,则表示用0对该对象初始化,例如:

int *p=new int();

(2)对于类类型的对象
要根据初始化参数列表的参数类型和个数调用该类的构造函数。

在用new建立一个对象时,如果该类存在用户自定义的默认构造函数,则“new T”和“new T()”这两种写法的效果时相同的,都会调用这个默认的构造函数。但若用户没有定义默认的构造函数,使用“new T”创建对象时,会调用系统生成的隐含的默认构造函数;使用“new T()”创建对象时,系统除了执行默认构造函数会执行的操作外,还会为基本数据类型和指针类型的成员用0赋初值,而且这一过程是递归的。也就是说,如果该对象的某个成员对象也没有用户自定义的默认构造函数,那么对该成员的基本数据类型和指针类型的成员,同样会被以0赋初值。

2.运算符delete是用来删除由new建立的对象,释放指针所指向的内存空间。

格式为:

delete 指针名;

如果删除的是对象,该对象的析构函数将被调用。对于new建立的对象,只能用delete进行一次删除操作,如果同一内存空间多次使用delete进行删除将会导致运行错误。

【注意】用new分配的内存,必须用delete加以释放,否则会导致动态内存分配的内存无法回收,使得程序占据的内存越来越大,这叫做“内存泄漏”。

【例】动态创建对象

class Point
{
public:
	Point() :x(0), y(0)
	{
		cout << "调用默认构造函数" << endl;
	}

	Point(int x, int y) :x(x), y(y)
	{
		cout << "调用构造函数" << endl;
	}
	~Point()
	{
		cout << "调用析构函数" << endl;
	}
	int getX() { return x; }
	int getY() { return y; }
	void move(int newX, int newY)
	{
		x = newX;
		y = newY;
	}
private:
	int x, y;
};

int main()
{
	cout << "创建第一个对象:" << endl;
	Point* p1 = new Point;//动态创建对象,没有给出参数列表,因此调用默认的构造函数
	delete p1;//删除对象,自动调用析构函数

	cout << "创建第一个对象:" << endl;
	Point* p2 = new Point(1,2);//动态创建对象,并给出参数列表,因此调用有参数的构造函数
	delete p2;//删除对象,自动调用析构函数

	return 0;
}

运行结果:
在这里插入图片描述
3.使用运算符new也可以创建数组对象,这时需要给出数组的结构说明。用new运算符动态创建一维数组的语法形式为:

new 类型名[数组长度]

其中数组长度指出了数组元素的个数,它可以是任何能够得到正整数值得表达式。

用new动态创建一维数组时,在方括号后面仍然可以加小括号“()”,但小括号内不能带参数。是否加“()”得区别在于,不加“()”,则对数组每个元素得初始化,与执行“new T”时所进行得初始化方式相同;加“()”,则与执行“new T”所进行初始化得方式相同。例如,如果这样动态生成一个整型数组:

int *p=new int[10]();

则可以方便地为动态创建的数组用()初始化。

如果是用new建立得数组,用delete删除时在指针名前面要加“[]”,格式如下:

delete []指针名;

【例】动态创建对象数组

class Point
{
public:
	Point() :x(0), y(0)
	{
		cout << "调用默认构造函数" << endl;
	}

	Point(int x, int y) :x(x), y(y)
	{
		cout << "调用构造函数" << endl;
	}
	~Point()
	{
		cout << "调用析构函数" << endl;
	}
	int getX() { return x; }
	int getY() { return y; }
	void move(int newX, int newY)
	{
		x = newX;
		y = newY;
		cout <<"(" <<x <<"," << y<<")" << endl;
	}
private:
	int x, y;
};

int main()
{
	Point* p = new Point[2];
	p[0].move(5, 10);
	p[1].move(15, 20);
	cout << "删除对象:" << endl;
	delete[]p;
	return 0;
}

运行结果:
在这里插入图片描述
这是利用动态内存分配操作实现了数组得动态创建,使得数组元素得个数可以根据运行时得需要而确定。但是建立和删除数组得过程使得程序略显繁琐,更好得方法是将数组得建立和删除封装起来,形成一个动态数组类。

另外,在动态数组类中,通过类得成员函数访问数组元素,可以每次在访问之间检查一下下标是否越界,使得数组下标越界得错误能够及早发现。这种检查,可以通过C++的assert来进行。assert的含义是“断言”,它是标准C++的cassert头文件中定义的一个宏,用来判断一个条件表达式的值是否为true,如果不为true,则程序会中止,并且报错,这样就很容易将错误定位。一个程序一般可以以两种模式编译——调试(debug)模式和发行(release)模式,assert只在调试模式下生效,而在发行模式下不执行任何操作,这样兼顾了调试模式的调试需求和发行模式的效率需求。

【注意】由于assert只在调试模式下生效,一般用assert只是检查程序本身的逻辑错误,而用户的不当输入造成的错误,则应当用其他方式加以处理。

【例】动态数组类

class Point
{
public:
	Point() :x(0), y(0)
	{
		cout << "调用默认构造函数" << endl;
	}

	Point(int x, int y) :x(x), y(y)
	{
		cout << "调用构造函数" << endl;
	}
	~Point()
	{
		cout << "调用析构函数" << endl;
	}
	int getX() { return x; }
	int getY() { return y; }
	void move(int newX, int newY)
	{
		x = newX;
		y = newY;
		cout << "(" << x << "," << y << ")" << endl;
	}
private:
	int x, y;
};
//动态数组类
class Arr
{
public:
	Arr(int size) :size(size)
	{
		points = new Point[size];
	}
	~Arr()
	{
		cout << "删除对象:" << endl;
		delete[]points;
	}
	//获得下标为index的数组元素
	Point& element(int index)
	{
		assert(index >= 0 && index < size);//如果数组下标越界,程序中止
		return points[index];
	}
private:
	Point* points;//指向动态数组的首地址
	int size;//数组大小
};

int main()
{
	int count;
	cout << "请输入要创建的对象的个数:";
	cin >> count;
	Arr points(count);//创建对象数组
	points.element(0).move(5,0);//访问数组元素的成员
	points.element(1).move(15,20);
	return 0;
}

运行结果:
在这里插入图片描述
在main函数中,只是建立一个Arr类的对象,对象的初始化参数size指定了数组元素的个数,创建和删除对象数组的过程都由Arr类的构造函数和析构函数完成。

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

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

相关文章

html页面input设置日期和时分秒组件方法

html <input class"form-control" type"datetime-local" step"01">效果图

Java根据坐标经纬度计算两点距离(5种方法)、校验经纬度是否在圆/多边形区域内的算法推荐

目录 前言 一、根据坐标经纬度计算两点距离&#xff08;5种方法&#xff09; 1.方法一 2.方法二 3.方法三 4.方法四 5.方法五 5.1 POM引入第三方依赖 5.2 代码 6.测试结果对比 二、校验经纬度是否在制定区域内 1.判断一个坐标是否在圆形区域内 2.判断一个坐标是否…

安防监控国标GB28181平台EasyGBS视频快照无法显示是什么原因?如何解决?

安防视频监控国标视频云服务EasyGBS支持设备/平台通过国标GB28181协议注册接入&#xff0c;并能实现视频的实时监控直播、录像、检索与回看、语音对讲、云存储、告警、平台级联等功能。平台部署简单、可拓展性强&#xff0c;支持将接入的视频流进行全终端、全平台分发&#xff…

【Leetcode刷题】模拟

本篇文章为 LeetCode 模拟模块的刷题笔记&#xff0c;仅供参考。 目录 一. 字符串Leetcode43.字符串相乘Leetcode592.分数加减运算Leetcode68.文本左右对齐 二. 矩阵Leetcode54.螺旋矩阵Leetcode885.螺旋矩阵 IIILeetcode498.对角线遍历Leetcode874.模拟行走机器人 三. 数组Lee…

Aligning Large Language Models with Human: A Survey

本文也是LLM相关的综述文章&#xff0c;针对《Aligning Large Language Models with Human: A Survey》的翻译。 对齐人类与大语言模型&#xff1a;综述 摘要1 引言2 对齐数据收集2.1 来自人类的指令2.1.1 NLP基准2.1.2 人工构造指令 2.2 来自强大LLM的指令2.2.1 自指令2.2.2 …

JavaSE【抽象类和接口】(抽象类、接口、实现多个接口、接口的继承)

一、抽象类 在 Java 中&#xff0c;一个类如果被 abstract 修饰称为抽象类&#xff0c;抽象类中被 abstract 修饰的方法称为抽象方法&#xff0c;抽象方法不用 给出具体的实现体。 1.语法 // 抽象类&#xff1a;被 abstract 修饰的类 public abstract class Shape { …

AI.com的命运之战:马斯克如何从OpenAI手中夺走这个价值千万的域名

一、AI.COM AI.com是一个极具价值的域名&#xff0c;它于1993年5月注册&#xff0c;距今已有近30年的历史。2021年2月&#xff0c;人工智能研究机构OpenAI以至少1100万美元&#xff08;约合人民币7535万元&#xff09;的高价&#xff0c;拿下了这个域名。OpenAI是马斯克在2015…

微信小程序中的分包使用介绍

一、分包的好处 可以优化小程序首次启动的下载时间 在多团队共同开发时可以更好的解耦协作 主包&#xff1a;放置默认启动页面/TabBar 页面&#xff0c;公共资源/JS 脚本 分包&#xff1a;根据开发者的配置进行划分 限制&#xff1a;所有分包大小不超过 20M&#xff0c;单…

私有化部署企业IM即时通讯:提升效率、防止泄密、高效协同办公

随着科技的飞速发展和智能手机的普及&#xff0c;即时通讯&#xff08;IM&#xff09;应用在我们的生活和工作中变得越来越重要。在企业中&#xff0c;IM已成为员工之间交流沟通的主要方式之一。然而&#xff0c;对于大多数企业来说&#xff0c;选择私有化部署企业IM即时通讯软…

Pytorch Tutorial【Chapter 2. Autograd】

Pytorch Tutorial 文章目录 Pytorch TutorialChapter 2. Autograd1. Review Matrix Calculus1.1 Definition向量对向量求导1.2 Definition标量对向量求导1.3 Definition标量对矩阵求导 2.关于autograd的说明3. grad的计算3.1 Manual手动计算3.2 backward()自动计算 Reference C…

解决在mybatis中使用class属性绑定映射文件出现的异常问题~

如下所示&#xff0c;当我在XML文件中通过class属性配置其mapper文件时&#xff0c;出现下述错误 <mappers><mapper class"mappers.userMapper"/> </mappers>错误描述&#xff1a; 解决方法如下所示&#xff1a;在pom.xml文件中添加下述代码 <…

【腾讯云Cloud Studio实战训练营】使用React快速构建点餐H5

文章目录 前言一、Cloud Studio是什么二、Cloud Studio特点三、Cloud Studio使用1.访问官网2.账号注册3.模板选择4.模板初始化5.H5开发安装 antd-mobile安装 Less安装 normalize&#xff1a;上传项目需要的素材&#xff1a;替换App.js主文件&#xff1a;项目启动、展示 6.发布仓…

zookeeper安装教程及其基本使用

目录 zookeeper下载&#xff1a; zookeeper下载官网&#xff1a; 本地安装配置&#xff1a; 启动zookeeper&#xff1a; 开启服务端&#xff1a; 启动客户端&#xff1a; 查看zookeeper的状态&#xff1a; zoo.cfg文件解读&#xff1a; zookeeper的集群安装&#xff1a…

Go调试神器pprof使用教程【实战分享】

Go调试神器pprof使用教程 go的GC会自动管理内存&#xff0c;但是这不代表go程序就不会内存泄露了。 go常见产生内存泄露的原因就是goroutine没有结束&#xff0c;简单说就是goroutine 被阻塞了&#xff0c;这样就会导致goroutine引用的内存不被GC回收。 1 概念 在Go中&#xf…

二叉树的性质、前中后序遍历【详细】

1. 树概念2.二叉树的概念1.2二叉树的性质 3.二叉树遍历3.2前序遍历3.2 中序遍历3.3 后序遍历 1. 树概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合&#xff0c;有二叉树&#xff0c;N叉树等等。 子树…

[CKA]考试之一个 Pod 封装多个容器

由于最新的CKA考试改版&#xff0c;不允许存储书签&#xff0c;本博客致力怎么一步步从官网把答案找到&#xff0c;如何修改把题做对&#xff0c;下面开始我们的 CKA之旅 题目为&#xff1a; Task 创建一个Pod&#xff0c;名字为kucc1&#xff0c;这个Pod包含4容器&#xff…

Python:Spider爬虫工程化入门到进阶(1)创建Scrapy爬虫项目

Python&#xff1a;Spider爬虫工程化入门到进阶系列: Python&#xff1a;Spider爬虫工程化入门到进阶&#xff08;1&#xff09;创建Scrapy爬虫项目Python&#xff1a;Spider爬虫工程化入门到进阶&#xff08;2&#xff09;使用Spider Admin Pro管理scrapy爬虫项目 本文通过简…

眼科医生推荐的台灯 护眼台灯买什么好?

我家孩子需要一个护眼灯&#xff0c;就请教了我的一个医生朋友。大家都知道医生白天对着电脑长时间的工作&#xff0c;晚上还要看书&#xff0c;查文献&#xff0c;写论文&#xff0c;选一个对眼睛友好的高质量护眼台灯对他们是刚需&#xff0c;同时又是医生&#xff0c;所以他…

网络安全(黑客)自学建议一一附学习路线

温馨提示&#xff1a;为了避免误入歧途&#xff0c;自学请优先看《网络安全法》。 下面是一些学习建议&#xff1a; 1、多请教有经验的人 切忌钻牛角尖&#xff0c;特别是刚入门的什么都不了解的情况下&#xff0c;可能你花好几天研究的一个东西&#xff0c;人10分钟就能搞定…