每个程序在执行时都占用一块可用的内存空间,用于存放动态分配的对象,此内存空间称为程序的*存储区(free store)或堆(heap)。C语言用一堆标准库函数malloc和free在*存储区中分配存储空间,而C++则用new和delete表达式实现相同的功能。
一、new和delete创建和释放动态数组:
数组类型的变量有三个重要的限制:数组长度固定,在编译时必须知道其长度,数组只在定义它的语句内存在。动态数组:长度固定,编译时不必知道其长度,通常是运行时确定;一直存在,直到程序显示释放它。
1、动态数组的定义:数组变量通过指定类型、数据名和维数来定义。而动态分配数组时,只需指定类型和数组长度,不必为数组对象命名,new表达式返回指向新分配数组的第一个元素的指针:int*pia=new int[10];在*存储区中创建的数组对象没有名字,只能通过其地址间接访问堆中的对象。
2、初始化动态分配的数组:若数组元素具有类类型,将使用该类的默认构造函数初始化;若数组元素是内置类型,则无初始化。也可跟在数组长度后面的一堆空圆括号,对数组元素做值初始化。
string *psa=newstring[10]; //array of 10 empty strings
int *pia=newint[10]; //array of 10 uninitializedints
int *pia2=newint[10](); //array of 10 zero
对于动态分配的数组,其元素只能初始化为元素类型的默认值,而不能像数组变量一样,用初始化列表为数组元素提供各不相同的初值。
3、const对象的动态数组:若在堆中创建的数组存储了内置类型的const对象,则必须为这个数组提供初始化:因数组元素都是const对象,无法复制。
const int*pci_ok=new const int[100]();
C++允许定义类类型的const数组,但该类型必须提供默认构造函数。
已创建的常量元素不允许修改,所以此类数组用处不大。
4、允许动态分配空数组:动态分配数组,多是由于编译时不知道数组长度。
size_t n=get_size(); int*p=new int[n];
C++虽然不允许定义长度为0的数组变量,但明确指出,调用new创建长度为0的数组是合法的。new返回有效的非零指针。该指针不能与new返回的其他指针不同,不能进行解引用操作,因它没指向任何元素。允许的操作:比较运算。
5、动态空间的释放:程序员必须显示将其占用的存储空间返还给程序的*存储区。C++语言为指针提供delete []表达式释放指针所指向的数组空间。
delete [] pia;[]告诉编译器该指针指向的是堆中的数组,而非单个对象,若遗漏,编译器无法发现。
二、new和delete创建和释放单个对象
定义变量时,必须指定其数据类型和名字。而动态创建对象时,只需指定其数据类型。new返回指向新创建对象的指针,通过该指针来访问此对象。
1、动态创建对象的初始化:int *pi=new int(1024)
2、动态创建对象的默认初始化:若不提供显式初始化,与函数内定义的变量初始化方式相同,类类型->默认构造函数;内置类型->无初始化。同样可做值初始化:
int *pi=newint();值初始化的()必须置于类型名后,而非变量后,int x()是声明函数。
3、撤销动态创建的对象:程序员必须显示将该对象占用的内存返回给*存储区。delete,若指针指向不是用new分配的内存地址,则对该指针使用delete非法。
int i; int *pi=&i; delete pi;//编译器不能断定一个指针指向什么类型的对象,因此大部分编译器仍能通过(VS2005编译通过,执行到该处报错)。
4、零指针的删除:int *ip=0; delete ip;若指针值为0,则delete合法。
5、delete后,重设指针值:delete p;删除指针后,p成为悬垂指针。悬垂指针指向曾经存放对象的内存,但该对象已不存在,引用该内存报错。所以一旦删除指针所指向的对象,立即将指针置为0。
6、const对象的动态分配和回收:创建时初始化,且一经初始化,其值不可修改。
const int*pci=new const int(1024);new表达式返回int型const对象的指针。所以只能赋给指向const的指针。内置类型对象或未提供默认构造函数的类类型对象必须显示初始化。
删除const对象:delete pci;
三、与动态内存分配相关的三种常见程序错误:
1、删除指向动态分配内存的指针失败,称为memory leak。一般需等程序运行一段时间,耗尽内存时,才显露出来。
2、读写已删除的对象。若删除指针所指对象后,置指针值为0,易检查出此类错误。
3、对同一个内存空间使用两次delete表达式。第二次delete时,*存储区可能被破坏。