学习线性表的过程中,知道了线性表的两种实现方式,一种是静态的一种是动态的,动态线性表的实现中经常可以看到分配空间的语句L = new Lnode,在释放的时候是delete L。虽然这样用,但是一直不知道为什么要这样用。
- 在C++中,动态内存管理是通过一对运算符来完成的,分别是new与delete。
- new:在动态内存中作为对象分配空间并返回一个指向该对象的指针。
- delete:接受一个动态对象的指针,销毁该对象,释放与之关联的内存。
- 缺点:使用动态内存很容易出问题,因为确保在正确的时间内释放内存是极其困难的。有时候会忘记释放内存,容易产生内存泄漏;还有在有其他指针引用内存的情况下我们就释放了它,这时会产生引用非法内存的指针。
- 为了解决上面的问题,C++标准库中提供了两种智能指针,可以复负责自动释放所指向的对象。分别为shared_pt和unique_ptr,还有一个weak_ptr的伴随类。这里简单了解,不在细说,具体等深入学习后在更新。
int *pia = new int[get_size]; //pia指向第一个int,调用get_size确定分配多少个int
//方括号内必须为整型,但不必是常量
//使用类型别名来分配数组
typedef int arrT[42]; //arrT表示42个int的数组类型
int *p = new arrT; //分配一个42个int的数组,p指向第一个int;
上述new分配了一个int数组,并返回指向第一个int的指针
注意:即使代码中没有方括号,但是编译器执行这个表达式的时候还是会用到new[],即编译器实际执行的时候是:int *p = new int[42];
-
分配一个数组会得到一个元素类型的指针
- 但使用new分配一个数组的时,我们并未得到一个数组类型的对象,而是得到一个数组元素类型的指针。即使我们使用类别定义了一个数组类型,new也不会分配一个数组类型的对象。new返回的是一个元素类型的指针。
-
初始化动态内存分配对象的数组
- 默认情况下,new分配的对象,不管是单个分配的还是数组中的,都是默认初始化的。对一个数组中的元素进行值初始化,方法是在大小之后跟一对空括号
int *pia = new int[10]; //10个未初始化的int
int *pia2 = new int[10](); //10个值初始化为0的int
int *pia3 = new int[10]{1,2,3,4,5,6,7,8,9,0}; //10个int分别用类别中对应的初始化器进行初始化
- 初始化器会用来初始化动态数组中开始部分的元素,如果初始化器数目小于元素数目,剩余元素将进行值初始化。如果初始化器数目大于元素数目,则new表达式失败,不会分配任何内存。
- 默认情况下,new分配的对象,不管是单个分配的还是数组中的,都是默认初始化的。对一个数组中的元素进行值初始化,方法是在大小之后跟一对空括号
-
假设分配的大小为
int *p = new int[0]
,new会返回一个合法的非空指针。该指针与new返回的其他任何指针都不相同,可以向此指针加上或减去0,也可以从此指针减去自身得到0。但是,此指针不能解引用,因为它不指向任何元素
释放动态内存
delete p; //p必须指向一个动态分配的对象或为空;
delete []pa; //pa必须指向一个动态分配的数值或为空;
- 第二条语句销毁pa指向的数组中的元素,并释放对应的内存,数组中的元素按照逆序销毁。也就是最后一个元素最先销毁,然后是倒数第二个,以此内推。
- 当释放一个指向数组的指针的时候,空方括号是必需的。它指示编译器此指针指向一个对象数组的第一个元素。
- 如果在delete一个指向数组的指针时未加上[],或者在对一个非数组的对象上加上[],这样的行为是未定义的,即是未知的。
这个时候,程序编译的时候不会出错,但我们的程序可能在执行过程中在没有任何警告的情况下行为异常。