Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2845082
  • 博文数量: 523
  • 博客积分: 11908
  • 博客等级: 上将
  • 技术积分: 5475
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-03 15:50
文章分类

全部博文(523)

文章存档

2019年(3)

2013年(4)

2012年(71)

2011年(78)

2010年(57)

2009年(310)

分类: C/C++

2009-09-14 10:10:01

前面介绍了如何使用new和delete表达式动态创建和释放数组,这两种表达式也可用于动态创建和释放单个对象.

定义变量时,必须指定其数据类型和名字.而动态创建对象时,只需指定其数据类型,而不必为该对象命名.取而代之的是,new表达式返回指向新创建对象的指针,我们通过该指针来访问此对象:

int i;  //named,uninitialized int variable
int *pi=new int; //pi points to dynamically allocated,
                 //unnamed,uninitialized int

这个new表达式在自由存储区中分配创建了一个整型对象,并返回此对象的地址,并用该地址初始化指针pi. 

1.动态创建对象的初始化

动态创建的对象可用初始化变量的方式实现初始化:

int i(1024);  //value of i is 1024
int *pi=new int(1024);  //object to which pi points is 1024
string s(10,'9');    //value of s is "9999999999"
string *ps=new string(10,'9');  //*ps is "9999999999"

C++使用直接初始化(derect-initialization)语法规则初始化动态创建的对象.如果提供了初值,new表达式分配到所需要的 内存后,用给定的初值初始化该内存空间.在本例中,pi所指向的新创建对象将被初始化为1024,而ps所指向的对象则初始化为十个9的字符串.

2.动态创建对象的默认初始化

如果不提供显式初始化,动态创建的对象与在函数内定义的变量初始化方式相同.对于类类型的对象,用该类的默认构造函数初始化;而内置类型的对象则无初始化.

string *ps=new string; //initialized to empty string
int *pi=new int;   //pi points to an uninitialized int

通常,除了对其赋值之外,对未初始化的对象所关联的值的任何使用都是没有定义的.

------------------------------------------------------------我是懒惰的分割线------------------------------------------------

实践告诉你:正如我们(几乎)总是要初始化定义为变量的对象一样,在动态创建对象时,(几乎)总是对它做初始化也是一个好办法.

----------------------------------------------------------我是懒惰的分割线--------------------------------------------------

同样也可对动态创建的对象做值初始化(value-initialize):

string *ps=new string();  //initialized to empty string
int *pi=new int();     //pi points to an int value-initialized to 0
cls *pc=new cls();     //pc points to a value-initialized object of type cls

以上表明程序员想通过在类型名后面使用一对内容为空的圆括号对动态创建的对象做值初始化.内容为空的圆括号表明虽然要做初始化,但实际上并未提供特 定的初值.对于提供了默认构造函数的类类型(例如string),没有必要对其对象进行值初始化:无论程序是明确地不初始化还是要求进行值初始化,都会自 动调用其默认构造函数初始化该对象.而对于内置类型或没有定义默认构造函数的类型,采用不同初始化方式则由显著的差别:

int *pi=new int;   //pi points to an uninitialized int
int *pi=new int(); //pi points to an int value-initialized to 0

第一个语句的int型变量没有初始化,而第二个语句的int型变量则被初始化为0.

----------------------------------------------------------我是微困的分割线-------------------------------------------------

小心:值初始化的()语法必须置于类型名后面,而不是变量后.正如: int x();  //does not value initialize x

这个语句声明了一个名为x、没有参数而且返回int值的函数.

----------------------------------------------------------我是微困的分割线-----------------------------------------------

3.耗尽内存.

尽管现代机器的内存容量越来越大,但是自由存储区总有可能被耗尽.如果程序用完了所有可用的内存,new表达式就有可能失败.如果new表达式无法获取需要的内存空间,系统将抛出名为bad_alloc的异常.我们后面将会介绍如何抛出异常.

4.撤销动态创建的对象

动态创建的对象用完后,程序员必须显式地将该对象占用的内存返回给自由存储区.C++提供了delete表达式释放指针所指向的地址空间.

delete pi;

该命令释放pi指向的int型对象所占用的内存空间

-------------------------------------------------------我是微困的分割线-----------------------------------------------------

注解:如果指针指向不是用new分配的内存地址,则在该指针上使用delete是不合法的.

--------------------------------------------------------困死了,困死了----------------------------------------------------------

C++没有明确定义如何释放指向不是用new分配的内存地址的指针.下面提供了一些安全的和不安全的delete表达式.

int i;
int *pi=&i;
string str="dwarves";
double *pd=new double(33);
delete str;  //error:str is not a dynamic object
delete pi;  //error:pi refers to a local
delete pd;   //ok

值得注意的是:编译器可能会拒绝编译str的delete语句.编译器知道str并不是一个指针,因此会在编译时就能检查出这个错误.第二个错误则比较隐蔽:通常来说,编译器不能断定一个指针指向什么类型的对象,因此尽管这个语句是错误的,但在大部分编译器上仍能通过.

5.零值指针的删除

如果指针的值为0,则在其上做delete操作是合法的,但这样做没有任何意义:

int *ip=0;
delete ip;  //ok:always ok to delete a pointer that is equal to 0

C++保证:删除0值的指针是安全的.

6.在delete之后,重设指针的值

执行语句

delete p;后,p变成没有定义.在很多机器上,尽管p没有定义,但仍然存放了它之前所指向对象的地址,然后p所指向的内存已经被释放,因此p不再有效.

删除指针后,该指针编程悬垂指针(dangling pointer).悬垂指针指向曾经存放对象的内存,但该对象已经不再存在了.悬垂指针往往导致程序错误,而且很难检测出来.

------------------------------------------------------------我要努 力!-----------------------------------------------------------------

实践告诉你:一旦删除了指针所指向的对象,立即将指针置为0,这样就非常清楚地表明指针不再指向任何对象.

-------------------------------------------------------------我要奋 斗!----------------------------------------------------------------

7.const对象的动态分配和回收

C++允许动态创建const对象:

//allocate and initialize a const object
const int *pci=new const int(1024);

与其他常量一样,动态创建的const对象必须在创建时初始化,并且一经初始化,其值就不能再修改.上述new表达式返回指向int型const对 象的指针.与其他const对象的地址一样,由于new返回的地址上存放的是const对象,因此该地址只能赋给指向const的指针.

对于类类型的const动态对象,如果该类提供了默认的构造函数,则此对象可隐式初始化:

//allocate default initialized const empty string
const string *pcs=new const string;

new表达式没有显式初始化pcs所指向的对象,而是隐式地将pcs所指向的对象初始化为空的string对象.内置类型对象或未提供默认构造函数的类类型对象必须显式初始化.

---------------------------------------------------------------我是分割线---------------------------------------------------

警告:动态内存的管理容易出错

下面三种常见的程序错误都与动态内存分配相关:

1.删除(delete)指向动态分配内存的指针失效,因而无法将该块内存返还给自由存储区.删除动态分配内存失败称为"内存泄漏(memory leak)".内存泄漏很难发现,一般需等应用程序运行了一段时间后,耗尽了所有内存空间时,内存泄漏才会显露出来.

2.读写已删除的对象.如果删除指针所指向的对象之后,将指针置为0值,则比较容易检测出这类错误.

3.对同一个内存空间使用两次delete表达式.当两个指针指向同一个动态创建的对象,删除时就会发生错误.如果在其中一个指针上做delete运算,将该对象的内存空间返还给自由存储区,然后接着delete第二个指针,此时则自由存储区可能会被破坏.

操纵动态分配的内存时,很容易发生上述错误,但这些错误却难以跟踪和修正.

--------------------------------------------------------------我是分割线--------------------------------------------------------

8.删除const对象

尽管程序员不能改变const对象的值,但可撤销对象本身.如同其他动态对象一样,const动态对象也是使用删除指针来释放的:

delete pci;  //ok:deletes a const object

即使delete表达式的操作数是指向int型const对象的指针,该语句同样有效地回收pci所指向的内容.

阅读(1396) | 评论(0) | 转发(0) |
0

上一篇: new 和delete 表达式

下一篇:C++中this指针

给主人留下些什么吧!~~