http://blog.163.com/liumaohua890413@126/blog/static/35785164201010954850292/
最近一直在啃 C++ Primer 中文版第4版,发现 C++中new和delete应用遍布全书,现对其使用作简单总结。在C++中,可以使用new和delete动态创建和释放数组或者单个对象,现在对它们的使用一一道来。
1.创建动态数组
数组类型的变量有三个重要的限制:数组长度固定不变,在编译时必须知道它的长度,数组只在定义它的块语句中存在。对于动态分配的数组,虽然长度是固定的,但是动态分配的数组不必在编译时知道其长度,可以(通常也是)在运行时才确定数组长度;同时,动态分配的数组一直存在直到程序显示释放为止,这样,我们就可以自己决定数组的存在与否了。
每个程序在执行时都占用一块可用的内存空间,用于存放动态分配的对象,此内存空间称为程序的自由存储区(free store)或堆(heap).C++语言使用new和delete在自由存储区中分配存储空间。
动态分配数组时,只需指定类型和数组长度,不必为数组对象命名,new表达式返回指向新分配数组的第一个元素的指针:
int *pia=new int[10];
此new表达式分配了一个含有10个int型元素的数组,并返回指向该数组第一个元素的指针。在自由存储区创建的数组对象是没有名字的,程序员只能通过其地址间接地访问堆中的对象。
动态分配数组时,如果数组元素具有类类型,将使用该类的默认构造函数实现初始化;如果数组元素是内置类型,则无初始化:
string *psa = new string[10]; // 调用string类的默认构造函数依次初始化数组中的每个元素。
int *pis = new int[10]; //无初始化值
可使用跟在数组长度后面的一对空圆括号,对数组元素作值初始化:
int *pis = new int[10](); //数组元素都设置为0
之所以要动态分配数组,往往是由于编译时并不知道数组的长度。C++中允许动态分配空数组:
size_t n = get_size();
int *p = new int[n];
for(int *q=p;q!=p+n;++q)
『/*处理数组元素的相关代码*/』
在上面的例子中,只有在程序运行时才能确定n的值。如果n的值为0,代码依然正确执行。C++中虽然不允许定义长度为0的数组变量,但是明确指出,调用new动态创建长度为0的数组是合法的。
char *cp = new char[10];
用new动态创建长度为0的数组时,new返回有效的非零指针,但不能进行解引用,因为它毕竟没有指向任何元素。
2. 动态创建单个对象
动态创建对象时,只需指定其数据类型,不必为该对象命名,new表达式返回指向新创建对象的指针,我们通过该指针来访问此对象:
int *pi = new int(1024);
string *ps = new string(10, '9');
在C++中使用直接初始化语法规则初始化动态创建的对象,上面的表达式就使用该语法规则初始化了动态创建的对象。对于类类型的对象,则使用该类类型的构造函数初始化对象。可对动态创建的对象做值初始化,如下所示:
string *ps = new string();
int *pi = new int();
对于提供了默认构造函数的类类型,没有必要进行值初始化。如果没有显示初始化动态创建的对象,则对于类类型的对象,用该类的默认构造函数初始化,对于内置类型的对象则无初始化。
3. 动态空间的释放
动态分配的内存最后必须进行释放。如果不需要动态创建的数组,我们必须显示地将其占用的存储空间返还给程序的自由存储区。C++中使用delete [ ]表达式释放指针所指向的数组空间:
delete [ ] pis;
该语句释放上面所创建的动态int型数组所占有的存储空间。在关键字delete和指针之间的[ ]告诉编译器该指针指向的是自由存储区中的数组,而并非单个对象。对于表达式
delete pi;
该命令释放了pi指向的int型对象所占用的内存空间。删除指针后,该指针变成悬垂指针(dangling pointer).悬垂指针指向曾今存放对象的内存但该对象已经不存在了。悬垂指针往往导致程序错误,而且很难检测出来。一旦删除了指针所指向的对象,立即将指针置为0,这样就非常清楚地表明指针不再指向任何对象
========================================================================
new和delete已经完全包含malloc和free的功能,并且更强大、方便、安全。使用动态分配内存时不能忘记释放内存,不要忘记出错处理!下面先看new和delete的基本使用方法。
#include
<iostream>using namespace
std;int
main ( ) { //基本数据类型int
*i =new int
; //没有初始值int
*j =new int
(100); //初始值为100float
*f =new float
(3.1415f); //初始值为3.14159 cout <<" i = " << *i << endl; cout <<" j = " << *j << endl; cout <<" f = " << *f << endl; //数组int
*iArr =new int
[3];for
(int
i=0; i<3; i++) { iArr[i] = (i+1)*10; cout << i << ": " << iArr[i] << endl; } //释放内存delete
i;delete
j;delete
f;delete
[]iArr; //注意数组的删除方法return
0; }
一般有2种处理方法,一是根据指针是否为空来判断,一是用例外出错处理所抛出的“bad_alloc”来处理。
#include
<iostream>#include
<new>using namespace
std;int
main ( ) { //判断指针是否为NULLdouble
*arr =new double
[100000];if
(!arr) { cout <<"内存分配出错!" << endl;return
1; }delete
[]arr; //例外出错处理try
{double
*p =new double
[100000];delete
[]p; }catch
(bad_alloc xa) { cout <<"内存分配出错!" << endl;return
1; } //强制例外时不抛出错误,这时必须要判断指针double
*ptr =new
(nothrow)double
[100000];if
(!ptr) { cout <<"内存分配出错!" << endl;return
1; }delete
[]ptr; cout <<"内存分配成功!" << endl;return
0; }
前面章节已经用了很多了。
#include
<iostream>using namespace
std;class
classA {int
x;public
: classA(int
x) {this
->x = x; }int
getX() {return
x; } };int
main ( ) { classA *p =new
classA(200); //调用构造函数if
(!p) { cout <<"内存分配出错!" << endl;return
1; } cout <<"x = " << p->getX() << endl;delete
p; //调用析构函数return
0; }