C++内存管理

Posted 可乐不解渴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++内存管理相关的知识,希望对你有一定的参考价值。


在这里插入图片描述

前言

  • 对于类型相同的的大量数据,我们可以用数组来存储。数组是一种静态内存分配方法,其长度是固定的,由数组定义语句确定,由编译系统予以分配。
    在程序的运行过程中,有时我们很难事先确定需要多少数组元素,只能按照预先估算的最大数量进行定义,这样会造成一大部分内存的浪费,而且一旦超过预先定义的最大个数,数组就会越界,造成程序异常。
    动态内存分配技术可以保证程序在运行过程中根据实际需要申请适量的内存,使用结束后还可以释放并返回给系统。C++通过new运算符和delete运算符实现动态内存分配。

如需查看C语言动态管理,请点击查看我往期博客。

new 运算

new运算的作用是按照指定的类型和大小动态地去分配内存,基本语法如下:
指针变量 = new 类型名 (初值列表);
其中:

  • 数据类型可以是内置的数据类型,也可以是用户自定义的复杂数据类型。
  • new 运算符在堆(内存)中创建一个由类型名指定类型的对象,如果创建成功,返回对象的地址,否则返回空指针nullptr
  • 初值列表给初被创建对象的初始值。
  • 由于返回的是地址,所以要用实现定义好的一个相同类型的指针变量去接收这个地址。

例①:

创建一个数据对象

	int* pi = new int(10);		//pi指向一个初始值为10的 int 型的对象
	
	//也可以使用分开定义,如下
	int* pj;
	pj = new int(10);

首先我们定义了一个整形指针pi,然后使用new运算符去申请内存空间来创建一个初始值为10的int型数据对象,最后返回创建好的数据对象的地址存入到pi当中。

创建多个数据对象----即数组

当然new运算符也可以像c语言当中的malloccalloc一样创建多个同类型的对象。new运算符创建动态数组时,需要给出数组的结构说明。其语法形式如下:
指针变量 = new 类型名 [下标表达式];
其中:

  • 下标表达式与数组初始化时的常量表达式不同,可以是变量表达式。
    new运算符申请内存失败时返回nullptr,申请一个动态数组往往需要一个较大的空间,因此在程序中需要使用new的返回值进行判断,看是否申请内存成功。

例②:

	int* pa;
	pa = new int[5];	//pa指向5个未初始化的int型数据对象的首地址
	//如果想要将pa在创建时就初始化好应改为如下代码
	pa = new int[5]{ 1,2,3,4};	//此时第一个int型的对象的值就为1,同理后面的对象依次是{}中给出的值
	//当{}中给初的数值的个数小于创建的对象个数时,会将其值默认初始化为0
	//也可以使用一条语句定义
	int*pa=new int[5];
	//如果像将其初始化则像上述代码一样修改即可

结果如下:
在这里插入图片描述

★注意

(1)用new运算符申请分配的内存空间必须用delete释放。
(2)delete作用的指针必须是由new分配内存空间的首地址。
(3)对于一个已分配内存的指针,只能用delete释放一次。
(4)newdelete运算实现了堆空间的动态分配,它在带来方便的同时也潜伏了可能的 隐患:使用new进行内存分配之后,忘记了使delete运算进行内存回收,即“内存泄露”,如 果程序长时间运行,则有可能因内存耗尽而使系统崩溃,所以对newdelete要养成配对使用的良好习惯。

delete 运算

当程序不需要由new分配的内存空间时,可以用delete释放这些空间。其语法格式如下:
delete 指针变量名;
如果删除的是动态数组,则语法格式如下:
delete[]指针变量名;
其中:

  • 括号[]表示用delete释放为多少个对象分配的地址,[]中不需要说明对象的个数。
  • 不管建立的动态数组是多少维,释放的格式都是一样的。

对于例①、②分配的空间,释放语句如例③一样:
例③:

	delete pi;
	delete []pa;

例④:

class Obj 
{ 
public: 
	 Obj(void); // 无参数的构造函数
	 Obj(int x); // 带一个参数的构造函数 

} 
void Test(void) 
{ 
	 Obj *a = new Obj; 
	 Obj *b = new Obj(1); // 初值为 1 
	 delete a; 
	 delete b; 
} 

如果用 new 创建对象数组,那么只能使用对象的无参数构造函数。例如

 Obj *objects = new Obj[100]; // 创建 100 个动态对象 

不能写成

Obj *objects = new Obj[100] (1);// 创建 100 个动态对象的同时赋初值 1 

在用 delete 释放对象数组时,留意不要丢了符号‘[]’。例如

delete []objects; // 正确的用法 
delete objects;  // 错误的用法 

后者相当于 delete objects[0],漏掉了另外 99 个对象。

面试题

一、malloc/free和new/delete的区别

  1. malloc和free函数new和delete操作符
  2. malloc申请的空间不会初始化,new可以初始化。
  3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可。
  4. malloc的返回值为void*, 在使用时必须强制类型转换new不需要,因为new后跟的是空间的类型。
  5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常。
  6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理。

二、如何一次在堆上申请4G的内存?

在32位平台下mallocnew最大能申请2GB左右的内存。
只需把我们的环境改成64位平台下即可申请成功4GB的内存。
在64位平台下最大能申请的内存大小约为160亿GB左右
在这里插入图片描述
END...

以上是关于C++内存管理的主要内容,如果未能解决你的问题,请参考以下文章

C++内存管理机制

C/C++内存管理详解

C/C++内存管理详解

C++内存管理-内存池3

C++内存管理

内存管理c++