内容管理(C++)

以下测试都是在 VS2019环境下测试。

new 和 delete

对于内置类型

在C语言中,我们动态开辟内存用的是 m a l l o c malloc malloc f r e e free free,而在C++中,则是 n e w new new d e l e t e delete delete

int main()
{
	int* p1 = new int; // malloc
	int* p2 = new int[10]{ 0 };

	delete p1;
	delete [] p2;

	return 0;
}

在C++中,我们都用 n e w new new 来开辟空间,语法格式如下:

n e w new new + 类型 (对象个数) {初始化}

释放空间使用 d e l e t e delete delete 。对于内置类型来说本质上和 m a l l o c malloc malloc f r e e free free 是没有区别的。

在这里插入图片描述
如上图所示:对于这两个来说,本质都是去调用 m a l l o c malloc malloc f r e e free free

对于自定类型

class A
{
private:
	int _aa = 0;
public:
	void Print()
	{
		cout << "void Print()" << endl;
	}
	A(int _x = 0)
		:_aa(_x)
	{
		cout << "A()" << endl;
	};

	~A() 
	{
		cout << "~A()" << endl;
	};

	A(const A& AA)
	{
		_aa = AA._aa;
	}
};

在这里插入图片描述

对于自定义类型来说我们的 n e w new new 或去调用默认的构造函数, d e l e t e delete delete 会去调用析构函数。这就是 n e w new new d e l e t e delete delete 和 C语言中 m a l l o c malloc malloc f r e e free free 的区别。

operator new 和 operator delete

这两个函数是干什么的呢?

operator new 约等于 malloc
operator delete 与等于 free

在这里插入图片描述

在这里插入图片描述
对于 n e w new new 来说,他会先去调用 operator new 来开辟空间,然后再调用自定义类型的构造函数。


在这里插入图片描述

而对于 d e l e t e delete delete 来说,它先去调用 自定义类型的析构,然后再去调用 operator delete。

new 可以抛异常

在C语言中,我们 每次使用 m a l l o c malloc malloc都要去检查返回值,如果开辟失败, m a l l o c malloc malloc 返回 N U L L NULL NULL,而在C++中则是抛异常。以下是一个简单示例:
在这里插入图片描述
所以 n e w new new 我们就不需要像C语言那样每次使用 m a l l o c malloc malloc 都要去检查返回值,如上图,当我们遇到异常(空间开辟异常)直接抛异常,不会执行下面的代码,但这里会出现一个问题,那就是前面开辟的并没有释放,存在内存泄漏(以后学的更加深入了再来解决…)。

在这里插入图片描述
这里只需要记住:

n e w new new = 先 o p e r a t o r operator operator n e w new new + 再 构造
d e l e t e delete delete = 先 析构 + 再 o p e r a t o r operator operator d e l e t e delete delete

new[] 和 delete[]

这里的 n e w [ ] new[] new[] 是依次开辟 n n n个对象,每个对象都去调用构造函数,同时 d e l e t e [ ] delete[] delete[] 每个对象都要去调用 析构函数。

在这里插入图片描述

同时 这些方法最好是配套使用

例如: 用了 n e w new new 了 最好用 d e l e t e delete delete
用了 n e w p [ ] newp[] newp[] 最好用 d e l e t e [ ] delete[] delete[]。尤其是这种。
在这里插入图片描述
这里我们的A对象只有一个成员变量,根据以往的知识直到我们类的大小计算时,成员函数等是不计算的。所以我们开辟10个应该只需要40个字节啊?可是他这里为什么给了44个呢?

在这里插入图片描述
而这时,当我们把析构函数的显示定义关了之后,有只有40个字节了。

直接说结论:对于自定义类型来说,我们使用 n e w [ ] new[] new[]开辟空间之后会默认再多开辟一个4个字节的空间,存储我们后续需要析构的次数。就像这样一样:
在这里插入图片描述
我们会在p2的前面再开辟一个空间,来存储对象的数量。这个时候我们就必须要调用 d e l e t e [ ] delete[] delete[] 来释放空间了。如果只用 d e l e t e delete delete 来释放空间。编译器只会释放 p2 往后,那么前面那个空间就没有 释放掉,就会报错。这也是为什么我们要强调最好配套使用

在这里插入图片描述
当我们需要析构(显示定义析构)的时候,编译器会调整位置到前面那个存储析构次数的位置上,然后再调用 o p e r a t o r operator operator d e l e t e [ ] delete[] delete[] 来释放空间。
在这里插入图片描述
同时, o p e r a t o r operator operator d e l e t e [ ] delete[] delete[] 本质上是调用 o p e r a t o r operator operator d e l e t e delete delete o p e r a t o r operator operator d e l e t e delete delete 又是去调用的 f r e e free free

(补充)定位new

对于自定义类型而言,我们析构函数可以显示调用,但是构造函数却不可以。

这里的 operator new 只是单独开辟一块空间,并不进行任何其他活动。(就是malloc)。
在这里插入图片描述
那对于我们 operator new 开辟的空间(自定义类型)如何调用构造函数呢?

在这里插入图片描述
语法格式:

n e w new new + (地址) + 类型名 + {初始化列表}。

地址就像上图的 p2,初始化列表就是我们构造的形式(单参数,多参数)。

再来看一下多参数:

在这里插入图片描述
开辟多个对象:

在这里插入图片描述

总结

对于我们使用 n e w new new d e l e t e delete delete的时候我们直接配套使用就可以了,最好不要混着使用。

当我们使用 n e w new new [ ] [] [] 开辟空间但我们却使用 f r e e free free 释放空间的时候,我们并没有正确的释放空间(我们并没有调整到存储析构次数空间的那个位置)。所以运行报错。
在这里插入图片描述
如下图:此时我们又可以运行了,因为此时我们并不有显示定义,所以前面不会开辟那个空间存储析构次数,所以运行并没有报错,但是这只是因为我们类 A 里面并没有资源空间,如果我们有资源空间但是我们不显示定义析构的时候还是会出问题(同一片空间析构两次问题(栈:两个栈拷贝构造浅拷贝指向同一份空间,析构的也是同一份空间,free一块已经free得空间))。
在这里插入图片描述
所以:在使用的时候我们要配套使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值