C++内存管理

本文介绍了C++中的内存管理,包括new和delete关键字的使用,以及operatornew和operatordelete的作用。new用于动态内存分配,会调用构造函数,而delete则负责释放内存并调用析构函数。operatornew和operatordelete是对malloc和free的封装,提供异常处理。文章强调了new和delete配套使用的重要性,避免内存泄漏,并指出直接使用malloc/free可能存在的问题。

前言

我们先来回顾一下C语言的内存管理
内存分为这几个段:
栈区:非静态的局部变量都是存在栈区的,它是向下增长的。
堆区:用于程序运行时动态内存分配,它是向上增长的。
数据段:存在全局变量和静态变量。
代码段:可执行代码、常量。
而在堆区动态内存开辟的函数有malloc、calloc、realloc。
malloc和calloc的区别在于,前者开辟空间不初始化,而后者会初始化为0.
realloc是扩容。
C++是兼容C语言的,所以,它们两个的内存管理是差不多的。

new关键字

在C++中搞出一套新的动态内存开辟的方式:new
先说明一点,在C语言中malloc、calloc、realloc是函数,需要包头文件的,而new是关键字,直接用就可以,方式如下:

#include<iostream>

using namespace std;

int main()
{
	int* a = new int;//从堆区开辟4个字节的空间
	return 0;
}

开辟出来的空间里里面的值是未定义的,是随机值,我们可以在开辟孔家的时候就给它初始化:

#include<iostream>

using namespace std;

int main()
{
	int* a = new int(1);
	return 0;
}

也可以开辟数组,并且初始化:

#include<iostream>

using namespace std;

int main()
{
	int* a = new int(1);
	int* arr = new int[10]{ 0 };
	return 0;
}

在这里插入图片描述

delete关键字

C语言有free来释放空间,C++用的就是delete来释放空间,普通变量直接用delete,数组就需要在后面加上[]:

int main()
{
	int* a = new int(1);
	int* arr = new int[10]{ 0 };
	delete a;
	delete[] arr;
	return 0;
}

那如果我用new开辟的空间,能用free来释放吗,或者说malloc开辟的空间,能用delete释放吗?
答案是:分情况。
如果是下面这种情况,也是没问题的

int main()
{
	int* arr = (int*)malloc(sizeof(int));
	if (arr == nullptr)
	{
		perror("malloc fail");
		exit(-1);
	}
	delete arr;
	return 0;
}

只不过编译器会报出警告:
在这里插入图片描述
但是有一种情况会出问题:

class Stack
{
public:
	Stack(int size = 0,int capacity = 0)
	{
		arr = (int*)malloc(sizeof(int) * 4);
		if (arr == nullptr)
		{
			perror("malloc fail");
			exit(-1);
		}
		capacity = 4;
	}

	~Stack()
	{
		free(arr);
		arr = nullptr;
		cout << "资源已清理" << endl;
		sz = capacity = 0;
	}
private:
	int* arr;
	int sz;
	int capacity;
};

int main()
{
	Stack* st = new Stack;
	free(st);
	return 0;
}

这是一个栈类,里面动态开辟了一个数组,然后我们new一个栈的对象,最后用free来释放空间,free此时释放的空间是栈类实例化出来的对象的,而对象里面开辟的空间没有释放,会造成内存泄漏。
调试也可以看出,释放空间并没有调用栈这个类的析构函数
在这里插入图片描述
其实,关于new和delete的使用还有一点没有说明:
new:如果new的类型是自定义类型,会调用它的构造函数
delete:释放空间也是如此,会自动调用它的析构函数
还有一点要说明:

class A
{
private:
	int a;
};

int main()
{
	A* a = new A[10];
	free(A);
	return 0;
}

上面这个代码是直接编译不通过,说是不允许使用类型名,还有一点原因:
其实new在开辟空间得时候会在前面多开4个字节的空间,这4个字节的空间用来存储一共要调用多少次析构函数的次数
在这里插入图片描述
如果直接用free,其实释放的位置错了,所以会直接报错
如果用delete[] 来释放空间,它会自动往前面挪4个字节,然后解引用,就会知道要调用10次析构函数,然后释放后面的空间。
总结:最好还是配套使用,即malloc出来的空间就用free,new出来的就用delete。

operator new和operator delete

它们不是运算符重载,它们是定义在标准库中的,它们是干嘛的呢?
其实,它们就是对malloc和free进行封装:
operator new:对malloc进行封装,只是malloc开辟空间失败是返回空,而operator new开辟失败是抛出异常。
operator delete:同理,对free进行封装。
所以,operator delete最终还是用free来释放。

new、delete实现原理

new是会先调用operator new申请空间,如果申请失败抛出异常,否则,继续调用构造函数。
而delete是先调用析构函数、再调用operator delete释放空间。
上面的过程只是针对自定义类型,对于内置类型,和C语言的malloc、free没什么区别,毕竟new的底层还是用的malloc,delete的底层还是用的free。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值