动态内存管理

对于动态内存的管理,可以使用malloc和free申请和释放空间, 并且对于内置类型它是有能力初始化的,那如果是自定义类型该怎么办,一般成员变量是私有,在外面不能轻易访问,这种方式仅仅只能做到开辟空间而不能初始化。

C 语言内存管理方式在 C++ 中可以继续使用,但在自定义类型初始化的问题上就无能为力,而且使用起来比较麻烦,因此C++ 又提出了自己的内存管理方式: 通过 new delete 操作符进行动态内存管理

1.new的用法

当我们希望一块申请的空间不会随意被销毁时,用new来申请空间,new是在堆上开辟的空间,故不会被随意销毁。

new 类型 即可申请一个该类型大小的空间

int *p1 = new int;
但是它并不会完成初始化,如果想要初始化呢
new 类型(初始化的值) 即可完成初始化
int *p2 = new int(0);

在实际应用中,大部分情况都希望申请多个空间,申请多个空间的方式是:

new 类型[类型数量] 

int *p3 = new int[5];

与单个类型的初始化不同,这里想要初始化就不是一个括号,而是需借助{}

new 类型[类型数量]{初始化内容}

int *p4 = new int[5]{1, 2, 3 , 4, 5};

当new的初始化是不完全初始化,比如这里的int类型,后面的数据都会初始化为0

int类型是内置类型,自定义类型该如何初始化
首先创建一个类A,并创建一个a对象,然后拿a来初始化
class A
{
public:
	A(int a=0)
	{
		cout << "A(int a=0)" << endl;
		_a = a;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a;
};
void Test2()
{
	A *p1 = (A*)malloc(sizeof(A) * 5);
	A a(0);
	A *p2 = new A[5]{a};
}

通过调试可以看到,p2指向的五个成员的确是被初始化成了a

考虑到A类只有_a一个成员变量,完成初始化都无需创建a这个对象,直接拿0初始化结果一样

A *p2 = new A[5]{0};

之所以能直接拿0初始化,其实是编译器完成了隐式类型转换,先将0转换为A类,然后在拿这个A类去初始化p2里面的成员。

这样看,new好像仅仅是在堆上申请了空间,事实上new除了开辟空间它还做了一件事情,调用构造函数。

为了方便观察,每调用一次构造函数就打印出来

那这就好了,既然可以调用构造函数,不管自定义类型有多少个成员变量,统统都可以在构造函数里面初始化。

2.delete的用法

有申请空间就一定有释放空间,有new就一定有delete,delete和new的关系就和free和malloc的关系是一样的,都是捆绑使用。

不同的是,delete释放空间分为两种情况,首先是只new了一个类型的大小,直接delete即可

而new开辟了一种类型的多个对象空间,需要加上[]

void Test4()
{
	A *p1 = new A(0);
	A *p2 = new A[5]{0};
	//...
	delete p1;
	delete[] p2;
}
注意:申请和释放单个元素的空间,使用 new delete 操作符,申请和释放连续的空间,使用
new[] delete[],一定要匹配起来使用

delete的作用不仅限于释放空间,new会调用构造函数,同理,delete就会去调用析构函数,而且是先调用析构函数,然后在释放空间

delete[] 的原理
1. 在释放的对象空间上执行 N 次析构函数,完成 N 个对象中资源的清理
2. 调用 operator delete[] 释放空间,实际在 operator delete[] 中调用 operator delete 来释
放空间
malloc/free new/delete都是从堆上申请空间,并且需要用户手动释放。
而且在处理内置类型的方式上,new/delete和malloc/free非常相似,可以说几乎没区别。
下面来说它们不同的地方:

3.new/delete和malloc/free的区别

在申请自定义类型的空间时,new/delete除了能够申请/释放空间,还能调用对应的构造函数/析构函数,而malloc/free不可以。

处理申请内存失败情况的方式有所差异,malloc申请内存失败时会返回一个空指针,而new申请内存失败则是抛异常。因此使用malloc避免不了判断空指针,使用new避免不了捕获异常。

并且,new开辟空间明显会比malloc方便许多,malloc每次开辟空间都要算大小,还要在前面强制类型转换一下,new不需要这些繁琐的步骤,如果是多个对象,直接在[]里面指定对象个数,类型也会自动识别。

 还有就是之前提到的自定义类型初始化的问题,malloc无法做到,而new很好的解决了自定义类型初始化问题。

但其实这些都不是malloc/free和new/delete最本质的区别,他们最本质的区别是,malloc/free是函数,而new/delete是操作符。

4.动态内存管理带来的问题
不正确的使用动态内存开辟会带来一些危害,动态内存管理最主要的问题就是内存泄漏
什么是内存泄漏?
内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内
存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对
该段内存的控制,因而造成了内存的浪费。
有哪些方面的内存泄漏?
C/C++ 程序中一般我们关心两种方面的内存泄漏:
堆内存泄漏 (Heap leak)
堆内存指的是程序执行中依据须要分配通过 malloc / calloc / realloc / new 等从堆中分配的一
块内存,用完后必须通过调用相应的 free 或者 delete 删掉。假设程序的设计错误导致这部分
内存没有被释放,那么以后这部分空间将无法再被使用,就会产生 Heap Leak
系统资源泄漏
指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放
掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。
内存泄漏会带来什么危害?
长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值