一般来说用new []创建的对象要用delete[]销毁(基本类型new[]创建的对象也可以用delete销毁),对于new和delete在实现上还是调用的malloc和free。
对于基本类型在销毁的时候字需要释放malloc申请的空间就可以了;
但是对于类类型销毁的时候除了需要释放malloc申请的空间之外,还需要调用对象的析构函数
在对象中可能有指针成员指向一个动态申请的内存空间,上面提到的释放申请的空间的时候只是释放了这个指针占用的空间,对于指针指向的空间,需要在析构函数中释放。
对于基本类型和类类型的new[]和delete[]在实现上稍有差别:
1. 对于基本类型new[]直接调用malloc,delete[]直接调用free,所以delete和delete[]是没有区别的。
2. 对于类类型,new[]除了调用malloc申请空间之外,还会调用构造函数对每一个对象初始化;
更重要的是,对象数组的起始地址不是malloc放回的地址p,而是p后面的四个字节处。
那么p开始的四个字节用来做什么呢?
在这四个字节的地方保存了数组中对象的个数
但是为什么要保存对象的个数呢?
原因就是对象的析构。当用malloc申请内存的时候,系统按照某个大小的块规格分配,那么就可能造成实际分配的空间比我们申请的空间要大。在系统中记录着实际分配的空间大小,当释放这个空间的时候只需要提供这个空间的起始地址,系统就可以正确释放这个空间。
对于基本类型释放实际申请的空间就可以了,但是对于类类型,前面说过了还需要调用析构函数,但是有多少个对象需要调用析构函数呢?系统不能用分配的内存数/对象大小吗?
当然不行,前面说过了,系统记录的是实际分配的空间大小,后面包括了一些我们没有用到的空间。所以一定要记录对象的数目。
3. 当类类型调用delete[]的时候,首先从数组起始位置arr的前四个字节取出对象的个数n;
然后依次调用arr,arr+sizeof(object), .......,arr+sizeof(object)*(n-1)位置对象的析构函数;
最后系统通过 (int *)arr - 1地址释放当时malloc申请的实际内存。