C++ new与malloc和delete及free动态内存管理及区别介绍
Huuaaaaa 人气:0一般情况-堆上申请普通变量空间
申请堆空间时,实验表明 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 [ ]释放时候的析构函数调用。
加载全部内容