版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、动态内存分配程序运行时动态内存分配(dynamic memory allocation)先复习概念与方法、堆对象与构造函数 然后进一步讨论拷贝构造函数.1堆内存分配 通常编译器在编译时都可以根据变量(或对象)的类型知道所需内存空间的大小,从而在适当的时候为他们分配确定的存储空间。这种内存分配称为静态存储分配。 有些操作对象只有在程序运行时才能确定,系统根据运行时的要求进行内存分配,这种方法称为动态存储分配。21. 堆内存的分配与释放根据申请动态分配,用后显式释放所空间,使系统能做到重复使用有限的资源。格式如下:指针变量名=new 类型名(初始化式);delete 指针变量名;new运算符返回的
2、是一个指向所分配类型变量(对象)的指针。对所创建的变量或对象,都是通过该指针来间接操作的,而动态创建的对象本身没有名字。 3 堆区不会自动在分配时做初始化(包括清零),所以必须用初始化操作(initializer)来显式初始化。从堆区分配对象时,new表达式调用库操作符new()。例如: int *pi = new int(0); /对象未命名它与下列代码序列大体等价:int what=0;int *pi=&what;0pi4堆i演示:用初始化式(initializer)来显式初始化 int *pi=new int(0);当pi生命周期结束时,必须释放pi所指向的目标: delete pi;注
3、意这时释放了pi所指的目标的内存空间,也就是撤销了该目标,称动态内存释放(dynamic memory deallocation),但指针pi本身并没有撤销,该指针所占内存空间并未释放。 5对于数组进行动态分配的格式为: 指针变量名=new 类型名下标表达式;释放: Delete 指向该数组的指针变量名;如果delete语句中少了方括号,因编译器认为该指针是指向数组第一个元素的指针,会产生回收不彻底的问题(只回收了第一个元素所占空间),加了方括号后就转化为指向数组的指针,回收整个数组。6#include void main()int n;char *pc;cout请输入动态数组的元素个数n;
4、/在运行时确定,可输入17pc=new charn;strcpy(pc,堆内存的动态分配);coutpcendl;delete pc; /释放pc所指向的n个字符的内存空间return ;堆内存的动态分配pc【例1】动态一维数组的建立与撤销7动态分配数组有三个特点:1. 变量n在编译时没有确定的值,而是在运行中输入,按运行时所需分配堆空间,这一点是动态分配的优点,可克服数组“大开小用”的弊端。delete pc是将n个字符的空间释放,而用delete pc则只释放了一个字符的空间;2. 如果有一个char *pc1,令pc1=p,同样可用delete pc1来释放该空间。尽管C+不对数组作边界
5、检查,但在堆空间分配时,对数组分配空间大小是纪录在案的。3. 没有初始化式,不可对数组初始化。 8两种方法:动态创建二维数组double *data, *score; /方法1: score = new doublemn; /方法2:data = new double *m; for(int j=0;jm;j+) dataj = new doublen; 9两种方法:释放二维数组/方法1: delete score; /方法2:for (int i=0;im;i+) delete datai; delete data; 10#includeusing namespace std;const i
6、nt m=4; /行数const int n=6; /列数void desarray( double (*)6 ); /函数声明void main() double (*score)n; /定义二级指针变量 score = new doublemn; /一次分配全部数组单元 if (score = 0) cout Could not allocate. ;exit(-1);【例2】动态创建和删除一个m*n个元素的数组。/方法一:采用指向二维数组的指针,一次分配11 for (int i=0;im;i+) /初始化数组元素 for (int j=0;jn;j+) scoreij=i*n+j; f
7、or ( i=0;im;i+) for (int j=0;jn;j+) coutscoreijt;coutendl; desarray(score); /调用函数撤消数组 return; 12/二维数组的撤销与内存释放:void desarray(double ( *score)n ) delete score; 13【例2】动态创建和删除一个m*n个元素的数组。/方法二:采用指针数组,二次分配const int m=4; /行数const int n=6; /列数/先看二维数组的动态创建:void main() double *data; /定义指针数组,相当于 *datam data =
8、new double *m; /设置行指针 if (data ) = 0) cout Could not allocate. Bye .;exit(-1); for(int j=0;jm;j+) dataj = new doublen; /分配一个一维数组为一行 if (dataj = 0) cout Could not allocate. Bye .;exit(-1); 14 for (int i=0;im;i+) for (int j=0;jn;j+) dataij=i*n+j; /初始化数组元素 print(data); /调用函数输出数据 destroy(data); /调用函数进行撤
9、销与内存释放 return; /再看二维数组的撤销与内存释放:void destroy(double *data) for (int i=0;im;i+) delete datai; delete data; /注意撤销次序,与设置相反15指针使用的几个问题:1. 动态分配失败。返回一个空指针(NULL),表示发生了异常,堆资源不足,分配失败。2. 指针删除与堆空间释放。删除一个指针p(delete p;)实际意思是删除了p所指的目标(变量或对象等),释放了它所占的堆空间,而不是删除本身,释放堆空间后,成了空悬指针。16内存泄漏(memory leak)和重复释放。 new与delete 是配
10、对使用的, delete只能释放堆空间。如果new返回的指针值丢失,则所分配的堆空间无法回收,称内存泄漏,同一空间重复释放也是危险的,因为该空间可能已另分配,所以必须妥善保存new返回的指针,以保证不发生内存泄漏,也必须保证不会重复释放堆内存空间。动态分配的变量或对象的生命期。无名对象的生命期并不依赖于建立它的作用域,比如在函数中建立的动态对象在函数返回后仍可使用。我们也称堆空间为自由空间(free store)就是这个原因。但必须记住释放该对象所占堆空间,并只能释放一次,在函数内建立,而在函数外释放是一件很容易失控的事,往往会出错。 172.堆对象与构造函数/ 动态创建对象class Poi
11、nt public: Point() X=Y=0; coutDefault Constructor called.n; Point(int xx,int yy) X=xx; Y=yy; cout Constructor called.n; Point() coutDestructor called.n; int GetX() return X; int GetY() return Y;void Move(int x,int y) X=x; Y=y; private: int X,Y;18int main() coutStep One:endl; Point *Ptr1=new Point; /
12、调用缺省构造函数 delete Ptr1; coutStep Two:endl; Ptr1=new Point(1,2); /调用带参构造函数 delete Ptr1; return 0;运行结果:Step One:Default Constructor called.Destructor called.Step Two:Constructor called.Destructor called.193.堆对象数组与构造函数 通过new建立的对象要调用构造函数,通过deletee删除对象也要调用析构函数。CGoods *pc;pc=new CGoods; /分配堆空间,并构造一个无名的CGood
13、s对象;.delete pc; /先析构,然后将内存空间返回给堆; 堆对象的生命期并不依赖于建立它的作用域,所以除非程序结束,堆对象(无名对象)的生命期不会到期,并且需要显式地用delete语句析构堆对象,上面的堆对象在执行delete语句时,C+自动调用其析构函数。20class CGoods char Name21; int Amount; float Price; float Total value;public: CGoods() ; /缺省构造函数 CGoods(char* name,int amount ,float price) strcpy(Name,name); Amount
14、=amount; Price=price; Total_value=price*amount; /下面注意如何使用:正因为构造函数可以有参数,所以new后面类(class)类型也可以有参数。这些参数即构造函数的参数。但对创建数组,则无参数,并只调用缺省的构造函数。见下例类说明:21下面注意如何使用:void main() int n; CGoods *pc,*pc1,*pc2; pc=new CGoods(“夏利2000”,10,118000); /调用三参数构造函数 pc1=new CGoods(); /调用缺省构造函数 cout输入商品类数组元素数n; pc2=new CGoodsn; /
15、动态建立数组,不能初始化,需调用n次缺省构造函数 delete pc; delete pc1; delete pc2;22例6-18 动态数组类class ArrayOfPointsprivate: Point *points; int numberOfPoints;public: ArrayOfPoints(int n) numberOfPoints=n; points=new Pointn; /动态创建数组 ArrayOfPoints() coutDeleting.endl; numberOfPoints=0; delete points; Point& Element(int n) re
16、turn pointsn; ;2323int main()int number;coutnumber; /创建对象数组 ArrayOfPoints points(number); /通过指针访问数组元素的成员 points.Element(0).Move(5,10); /通过指针访问数组元素的成员 points.Element(1).Move(15,20); 2424运行结果如下:Please enter the number of points:2Default Constructor called.Default Constructor called.Deleting.Destructor
17、 called.Destructor called.2525堆对象与构造函数这里再次强调: 由堆区创建对象数组,只能调用缺省的构造函数,不能调用其他任何构造函数。如果没有缺省的构造函数,则不能创建对象数组。264.浅拷贝与深拷贝 缺省拷贝构造函数,可用一个类对象初始化另一个类对象,称为缺省的按成员拷贝,而不是对整个类对象的按位拷贝。这称为浅拷贝。 P堆对象堆对象PP 图1. 浅拷贝 拷贝前拷贝后 27如果类中有一个数据成员为指针,该类的一个对象obj1中的这个指针p,指向了动态分配的一个堆对象,(参见图7.1拷贝前),如果用obj1按成员拷贝了一个对象obj2,这时obj2.p也指向同一个堆对
18、象。当析构时,如用缺省的析构函数,则动态分配的堆对象不能回收。如果在析构函数中有“delete p;”语句,则如果先析构函数obj1时,堆对象已经释放,以后再析构obj2时出现了二次释放的问题。这时就要重新定义拷贝的构造函数,给每个对象独立分配一个堆对象,称深拷贝。这时先拷贝对象主体,再为obj2分配一个堆对象,最后用obj1的堆对象拷贝obj2的堆对象。 28浅拷贝与深拷贝给每个对象独立分配一个堆对象,称深拷贝。这时先拷贝对象主体,再为obj2分配一个堆对象,最后用obj1的堆对象拷贝obj2的堆对象。 堆对象PP堆对象 图2 . 深拷贝 29结论:在类的某个数据成员为指针的情况下:浅拷贝实
19、现对象间数据元素的一一对应复制。(只复制指针值)深拷贝当被复制的对象数据成员是指针类型时,不仅复制该指针成员本身,而且将指针所指的对象进行复制。指针成员指向新复制的单元。30例6-20 对象的浅拷贝#includeusing namespace std;class Point /类的声明同例6-16 /;class ArrayOfPoints /类的声明同例6-18 /;31class Point public: Point() X=Y=0; coutDefault Constructor called.n; Point(int xx,int yy) X=xx; Y=yy; cout Cons
20、tructor called.n; Point() coutDestructor called.n; int GetX() return X; int GetY() return Y;void Move(int x,int y) X=x; Y=y; private: int X,Y;32class ArrayOfPoints public: ArrayOfPoints(int n) numberOfPoints=n; points=new Pointn; ArrayOfPoints() coutDeleting.number; ArrayOfPoints pointsArray1(number
21、); pointsArray1.Element(0).Move(5,10); pointsArray1.Element(1).Move(15,20); ArrayOfPoints pointsArray2(pointsArray1); /拷贝构造 coutCopy of pointsArray1:endl; coutPoint_0 of array2: pointsArray2.Element(0).GetX() , pointsArray2.Element(0).GetY()endl; coutPoint_1 of array2: pointsArray2.Element(1).GetX()
22、 , pointsArray2.Element(1).GetY()endl;3434 pointsArray1.Element(0).Move(25,30); /数据改变 pointsArray1.Element(1).Move(35,40); coutAfter the moving of pointsArray1:endl; coutPoint_0 of array2: pointsArray2.Element(0).GetX() , pointsArray2.Element(0).GetY()endl; coutPoint_1 of array2: pointsArray2.Elemen
23、t(1).GetX() , pointsArray2.Element(1).GetY()endl;3535运行结果如下:Please enter the number of points:2Default Constructor called.Default Constructor called.Copy of pointsArray1:Point_0 of array2: 5, 10Point_1 of array2: 15, 20After the moving of pointsArray1:Point_0 of array2: 25, 30Point_1 of array2: 35,
24、40Deleting.Destructor called.Destructor called.Deleting.接下来程序出现异常,也就是运行错误。3636拷贝前拷贝后pointsArray1的数组元素占用的内存pointsnumberOfPointspointsArray1pointsnumberOfPointspointsArray1pointsArray1的数组元素占用的内存pointsnumberOfPointspointsArray23737例6-21 对象的深拷贝#includeusing namespace std;class Point /类的声明同例6-16 ;class ArrayOfPoints public: ArrayOfPoints(ArrayOfPoints& pointsArray); /其它成员同例6-18 ;38ArrayOfPoints :ArrayOfPoints(ArrayOfPoints& pointsArray) numberOfPoints =pointsArray.numbe
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 幼儿园植树实践活动策划方案五篇
- 国外销售合同范本
- 技术服务项目合同模板
- 居家养老服务合同范本
- 商业合作保密合同
- 知识产权许可合同书范本
- 维修工程合同范本
- 版权交易平台服务合同
- 无人驾驶船舶技术革新与航运未来
- 我国合同法203条
- 2024至2030年中国女装行业市场发展监测及投资前景展望报告
- 7.1.2 直观图的画法-【中职专用】高一数学教材配套课件(高教版2021·基础模块下册)
- 皮肤癣菌病的分子诊断工具
- SL+575-2012水利水电工程水土保持技术规范
- SYT 6968-2021 油气输送管道工程水平定向钻穿越设计规范-PDF解密
- 人美版初中美术知识点汇总八年级全册
- 迅雷网盘最最最全影视资源-持续更新7.26
- 普通话培训班合作协议书
- 《西方思想经典》课件
- 中医诊疗设备种类目录
- 如何构建高效课堂课件
评论
0/150
提交评论