1. 对象数组中delete与delete[]的区别
1.1 释放动态分配的内存空间
- C++中对new申请的内存的释放方式有delete和delete[]两种方式。
(1)delete:释放new分配的单个对象指针指向的内存;
(2)delete[]:释放new[]分配的对象数组指针指向的内存;
1.2 关于 new[] 和 delete[]分为两种情况
- 基本数据类型分配和回收空间;
- 自定义类型分配和回收空间(即对象数组的内存管理);
1.3 基本数据类型分配和回收空间
针对内置类型(即基本数据类型)使用new分配后的不管是数组还是非数组形式内存空间用两种方式均可,如:
int *a = new int[10]; delete a;//正确 <=>等价于 delete[] a;//正确
代码示例:
#include <iostream>; using namespace std; int main() { int NUM = 3; int *a1 = new int[NUM]; cout<<a1<<endl; delete a1; cout<<"释放了a1的空间"<<endl; int *a2 = new int[NUM]; cout<<a2<<endl; delete[] a2; cout<<"释放了a2的空间"<<endl; system("pause"); return 0; } =>01294750 释放了a1的空间 01294750 释放了a2的空间
注:此种情况中的释放效果相同,原因在于:分配简单类型内存时,内存大小已经确定,系统可以记忆并且进行管理,在析构时,系统并不会调用析构函数。
它直接通过指针可以获取实际分配的内存空间,哪怕是一个数组内存空间(在分配过程中系统会记录分配内存的大小等信息,此信息保存在结构体_CrtMemBlockHeader中,具体情况可参看VC安装目录下CRT\SRC\DBGDEL.cpp)
1.4 自定义类型分配和回收空间(即对象数组的内存管理)
针对自定义类型使用new分配后的空间,若是数组形式的内存空间,两种方式效果截然不同,如:
T *a = new T[10]; delete a;//错误,仅释放了a指针指向的全部内存空间 但是只调用了a[0]对象的析构函数,剩下的从a[1]到a[9]这9个用户自行分配的对应内存空间将不能释放 从而造成内存泄漏。 <!=>效果截然不同 delete[] a;//正确,调用使用类对象的析构函数释放用户自己分配内存空间并且释放了a指针指向的全部内存空间。
错误程序示例:
#include <iostream>; using namespace std; class T { public: T() { cout <<"构造T"<<endl; } ~T() { cout <<"析构T"<<endl; } }; int main() { int NUM = 3; T *p1 = new T[NUM]; cout<<p1<<endl; delete p1;//错误释放语句 cout<<"释放了p1空间"<<endl; T *p2 = new T[NUM]; cout<<p2<<endl; delete[] p2;//正确释放语句 cout<<"释放了p2空间"<<endl; system("pause"); return 0; } =>构造T 构造T 构造T 010F4754 析构T 程序崩溃了Debug Assertion Failed! Expression:_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
正确程序示例:
#include <iostream>; using namespace std; class T { public: T() { cout <<"构造T"<<endl; } ~T() { cout <<"析构T"<<endl; } }; int main() { int NUM = 3; T *p1 = new T[NUM]; cout<<p1<<endl; delete[] p1;//正确释放语句 cout<<"释放了p1空间"<<endl; T *p2 = new T[NUM]; cout<<p2<<endl; delete[] p2;//正确释放语句 cout<<"释放了p2空间"<<endl; system("pause"); return 0; } =>构造T 构造T 构造T 1664754 析构T 析构T 析构T 释放了p1空间 构造T 构造T 构造T 1664754 析构T 析构T 析构T 释放了p2空间
注:在用这些类生成对象数组的时候,用delete[]来释放它们才是王道。
参考文献:
[1] 百度搜索关键字:delete与delete[]的区别