C++ new与malloc和delete及free动态内存管理及区别介绍

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

C++ new与malloc和delete及free动态内存管理及区别介绍

Huuaaaaa   2022-12-19 我要评论

一般情况-堆上申请普通变量空间

申请堆空间时,实验表明 new/malloc 与 delete/free 是可以混用的,即可以通过free()释放掉new出来的一块内存。

int main() {
	int *p = new int(123);
	delete p;
	//free(p);
}

特殊情况-堆上申请对象空间

class Person{
public:
	Person(){
		cout << "construct call ......" << endl;
	}
	~Person(){
		cout << "destruct call ......" << endl;
	}
private:
	int m_age;
};
int main() {
	Person *ptr = new Person();
	if (ptr != nullptr)
	{
		free(ptr);
	}
	return 0;
}

单步走看内存分布图:

可以看到,执行完free(ptr) 后,内存确实是被释放了。(补充一下:fd作为开始结束的标志,"cd cd cd cd"代表开辟的内存,四个字节)

但是!对于一个对象而言,new和delete关键字还额外做了 调用构造函数和调用析构函数这两个步骤。

可以看到,程序只调用了构造函数(new关键字产生),但是由于使用的是free(),因此并没有调用类中的析构函数。

一般情况-堆上申请普通数组空间

int main() {
	int *ptr = new int[10];
	delete[]ptr;
	//delete ptr;
	return 0;
}

我们知道,用new在堆上申请数组空间,一般delete的时候都需要加上[ ] ,即 delete[ ] 。

但实验表明,如果不涉及到类对象,不加[ ]也同样可以实现空间的释放,加不加[ ]是没有区别的。

特殊情况-堆上申请对象数组空间

int main() {
	Person *ptr = new Person[10];
	delete ptr;
	return 0;
}

当new一个对象数组时,如果没有用delete[ ] ,会发生崩溃报错:

修改成delete [ ] ptr后,程序正常运行,并调用了十次构造函数和十次析构函数:

进一步探索:为什么修改为delete [ ] 就会调用十次析构函数?它是如何知道创建了十个对象就一定会析构十个对象?

查看一下此种情况下的内存分布:

可以看到我们申请的堆对象数组空间(10个),仔细查看改起始地址的前一个地址,按道理这并不属于我们分配的空间,为什么会多一个地址?

0x011E4EC8 ,该地址保存的值显示为16进制,转换为十进制刚好为10(0a 00 00 00)。这个10代表着什么?

不妨修改一下这个地址,0a 00 00 00 修改成 07 00 00 00 后接着单步走:

此时原来的十个地址空间的确是完整的被释放了,但是析构函数只被调用了 7次!正好是自己修改的那个内存地址的值。

到这里可以得出结论: 编译器是如何记录new 创建出来数组对象的个数, 就是简单的在创建空间的前一个地址,记录了创建对象的个数,析构的时候就按照这个地址的值进行析构。

总结

1. 申请一个堆上的对象时,不允许混搭new/delete 必须搭配使用。

2. new [ ] 和 delete [ ] 一定要配套使用,特别是申请对象数组时。

3. vs编译器会在new [ ] 申请对象数组时,在堆开始的前4个字节写入当前数组的长度,用于记录delete [ ]释放时候的析构函数调用。

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们