C++从零开始的打怪升级之路(day8)

发布时间:2024年01月13日

这是关于一个普通双非本科大一学生的C++的学习记录贴

在此前,我学了一点点C语言还有简单的数据结构,如果有小伙伴想和我一起学习的,可以私信我交流分享学习资料

那么开启正题

今天学习了复习了C语言内存管理相关知识,在此基础上学习了C++的内存管理知识

1.C/C++内存分布

C和C++中程序的内存区域划分是这样的

1.栈,栈也叫做堆栈,存储非静态局部变量/函数参数/返回值等,栈是向下增长的(栈比较小)

2.内存映射段,是高效地IO映射方式,用于装载一个共享的动态内存库,用户可以使用系统接口创建共享内存,叫做程间通信

3.堆,用于程序运行时动态内存分配,堆是向上增长的(堆比较大)

4.数据段(静态区),存储全局变量和静态数据

5.代码段(常量区),存储可执行的代码/只读常量

2.C++内存管理方式

C语言中的malloc/calloc/realloc/free在C++中可以继续使用,但使用起来比较麻烦,因此C++提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理

2.1new/delete操作内置类型

int main()
{
	int* p1 = (int*)malloc(sizeof(int));
	int* p2 = new int;
	//int* p2 = new int(1);

	free(p1);
	delete p2;

	int* p3 = (int*)malloc(sizeof(int) * 10);
	int* p4 = new int[10];

	free(p3);
	delete[] p4;
	return 0;
}

new申请动态空间只需要new后面加上需要申请的类型(定义一个变量时可以后面加上圆括号对变量进行初始化),自动返回指针,delete释放空间只需要在其后加上需要释放空间名,申请和释放连续的空间时,用new[],delete[],需要匹配起来使用

C语言和C++的两种操作方法对于内置类型来说,是没有区别的,那C++为什么还要创造两个关键字呢,下面我们会得到答案

2.2new和delete操作自定义类型

class A
{
public:
	A()
	{
		cout << "A()" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
};

int main()
{
	A* a1 = (A*)malloc(sizeof(A));
	A* a2 = new A;

	free(a1);
	delete a2;
	return 0;
}

运行上面的代码,屏幕上会打印两行数据,这是因为new在创建对象时,会调用构造函数对他进行初始化,delete在销毁函数时,会调用析构函数对对象进行清理

3.operator new与operator delete函数

int main()
{
	A* a1 = (A*)malloc(sizeof(A));
	A* a2 = (A*)operator new (sizeof(A));
	A* a3 = new A(2);

	free(a1);
	operator delete(a2);
	delete a3;
	return 0;
}

new和delete是用户进行动态内存申请和释放的操作符,operator new和operator delete是系统提供的全局函数,new在底层调用opertor new全局函数来申请空间,delete在底层调用operator delete全局变量来释放空间

那这三组动态内存管理办法到底有什么区别呢

首先C语言是面向过程的语言,而由于C++是面向对象的语言,我们需要打造一个像new delete的关键字,为那为什么不直接通过malloc free来实现呢,因为在开空间失败时需要抛异常,但是malloc无法实现这样的功能,所以我们打造了operator new这样的函数来实现这样的功能,再由operator new来实现new,至于free和operator delete,它们两个没有区别

总结

malloc

operator new = malloc + 失败抛异常

new = operator new + 调用构造函数初始化

free

operator delete = free

delete = operator delete + 调用析构函数清理

(我们也可以再类里面实现自己专属的operator new)

4.定位new表达式(placement-new)

定位new表达式是在已分配的原始内存空间中调用构造函数初始化对象

?
int main()
{
	A* p1 = new A;

	//模拟上面的行为
	A* p2 = (A*)operator new(sizeof(A));
	//对已经存在的一块空间调用构造函数进行初始化
	//定位new/replacement new
	new(p2)A;//也可以加上()进行传参

	return 0;
}

?

使用场景:定位new表达式一般配合内存池使用,因为内存池分配的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化

5.常见考点

5.1malloc/free和new/delete的区别

共同点:都是在堆上申请空间,并且我们需要手动释放

不同点:

1.malloc和free是函数,new和delete是操作符

2.如果是内置类型,它们的处理方式一样,但如果是内置类型,new/delete会调用相应的构造函数/析构函数

3.malloc的返回值是void*需要强转,new不需要

4.申请失败时候malloc会返回0,new会抛异常

5.2内存泄漏

什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内 存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对 该段内存的控制,因而造成了内存的浪费

内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现 内存泄漏会导致响应越来越慢,最终卡死

内存泄漏分为 堆内存泄漏 和 系统资源泄漏

当然我们也有许多检测内存泄漏的工具(这里大家可以自行搜索)

为了避免内存泄漏,我们后面学到的智能指针也会有很大的用处

总结::C++对内存管理有一套自己的办法,它更符合面向对象的特性,也方便我们后面实现更复杂的问题

今天的博客就到这里了,后续内容明天分享,最近因为考试周原因不能更新太多内容,等考试周结束了再"快马加鞭"

新手第一次写博客,有不对的位置希望大佬们能够指出,也谢谢大家能看到这里,让我们一起学习进步吧!!!

文章来源:https://blog.csdn.net/2301_80764270/article/details/135562656
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。