欢迎来到三一文库! | 帮助中心 三一文库31doc.com 一个上传文档投稿赚钱的网站
三一文库
全部分类
  • 研究报告>
  • 工作总结>
  • 合同范本>
  • 心得体会>
  • 工作报告>
  • 党团相关>
  • 幼儿/小学教育>
  • 高等教育>
  • 经济/贸易/财会>
  • 建筑/环境>
  • 金融/证券>
  • 医学/心理学>
  • ImageVerifierCode 换一换
    首页 三一文库 > 资源分类 > PPT文档下载
     

    第9讲动态内存分配736304930.ppt

    • 资源ID:3137974       资源大小:931.02KB        全文页数:41页
    • 资源格式: PPT        下载积分:6
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录 QQ登录   微博登录  
    二维码
    微信扫一扫登录
    下载资源需要6
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    第9讲动态内存分配736304930.ppt

    第九讲 动态内存分配,教材:C+语言程序设计(第4版) 第6章 6.36.5、6.8,清华大学 郑 莉,目录,9.1 动态内存分配 9.2 用vector创建数组对象 9.3 深拷贝与浅拷贝 9.4 深度探索 9.5 小结,2,3,9.1 动态内存分配,动态申请内存操作符 new,new 类型名T(初始化参数列表) 功能:在程序执行期间,申请用于存放T类型对象的内存空间,并依初值列表赋以初值。 结果值:成功:T类型的指针,指向新分配的内存;失败:抛出异常。,4,9.1 动态内存分配,释放内存操作符delete,delete 指针p 功能:释放指针p所指向的内存。p必须是new操作的返回值。,例9-1(教材例6-16) 动态创建对象举例,5,#include using namespace std; class Point public: Point() : x(0), y(0) cout“Default Constructor called.“endl; Point(int x, int y) : x(x), y(y) cout “Constructor called.“endl; Point() cout“Destructor called.“endl; int getX() const return x; int getY() const return y; void move(int newX, int newY) x = newX; y = newY; private: int x, y; ;,9.1 动态内存分配,例9-1 (续),6,int main() cout “Step one: “ endl; Point *ptr1 = new Point;/调用缺省构造函数 delete ptr1; /删除对象,自动调用析构函数 cout “Step two: “ endl; ptr1 = new Point(1,2); delete ptr1; return 0; ,9.1 动态内存分配,运行结果: Step One: Default Constructor called. Destructor called. Step Two: Constructor called. Destructor called.,7,9.1 动态内存分配,申请和释放动态数组,分配:new 类型名T 数组长度 数组长度可以是任何表达式,在运行时计算 释放:delete 数组名p 释放指针p所指向的数组。p必须是用new分配得到的数组首地址。,例9-2(教材例6-17) 动态创建对象数组举例,8,#include using namespace std; class Point /类的声明同例6-16,略 ; int main() Point *ptr = new Point2; /创建对象数组 ptr0.move(5, 10); /通过指针访问数组元素的成员 ptr1.move(15, 20); /通过指针访问数组元素的成员 cout “Deleting.“ endl; delete ptr; /删除整个对象数组 return 0; ,9.1 动态内存分配,9,例9-2 (续),运行结果: Default Constructor called. Default Constructor called. Deleting. Destructor called. Destructor called.,9.1 动态内存分配,10,9.1 动态内存分配,将动态数组封装成类,更加简洁,便于管理 建立和删除数组的过程比较繁琐 封装成类后更加简洁,便于管理 可以在访问数组元素前检查下标是否越界 用assert来检查,assert只在调试时生效,例9-3(教材例6-18)动态数组类,11,#include #include using namespace std; class Point /类的声明同例6-16 ; class ArrayOfPoints /动态数组类 public: ArrayOfPoints(int size) : size(size) points = new Pointsize; ArrayOfPoints() cout = 0 ,9.1 动态内存分配,例9-3 (续),12,int main() int count; cout count; ArrayOfPoints points(count); /创建对象数组 /通过访问数组元素的成员 points.element(0).move(5, 0); /通过类访问数组元素的成员 points.element(1).move(15, 20); return 0; ,9.1 动态内存分配,13,例9-3 (续),运行结果: Please enter the number of points:2 Default Constructor called. Default Constructor called. Deleting. Destructor called. Destructor called.,9.1 动态内存分配,14,9.1 动态内存分配,动态创建多维数组,new 类型名T第1维长度第2维长度; 如果内存申请成功,new运算返回一个指向新分配内存首地址的指针,是一个T类型的数组,数组元素的个数为除最左边一维外各维下标表达式的乘积。 例如: char (*fp)3; fp = new char23;,15,9.1 动态内存分配,char (*fp)3;,fp,fp+1,例9-4(教材例6-19) 动态创建多维数组,16,#include using namespace std; int main() float (*cp)98 = new float898; for (int i = 0; i (i * 100 + j * 10 + k);,9.1 动态内存分配,例9-4 (续),17,for (int i = 0; i 8; i+) for (int j = 0; j 9; j+) for (int k = 0; k 8; k+) /将指针cp作为数组名使用,通过数组名和下标访问数组元素 cout cpijk “ “; cout endl; cout endl; delete cp; return 0; ,9.1 动态内存分配,18,用vector创建数组对象,为什么需要vector? 将动态数组封装,自动创建和删除 数组下标越界检查 例6-18中封装的ArrayOfPoints也提供了类似功能,但只适用于一种类型的数组 vector动态数组对象的定义 vector 数组对象名(数组长度); 例:vector arr(5) 建立大小为5的int数组,9.2 用vector创建数组对象,19,9.2 用vector创建数组对象,vector数组对象的使用,对数组元素的引用 与普通数组具有相同形式: 数组对象名 下标表达式 但vector数组对象名不表示数组首地址 获得数组长度 用size函数 数组对象名.size(),例9-5(教材例6-20)vector应用举例,20,#include #include using namespace std; /计算数组arr中元素的平均值 double average(const vector ,9.2 用vector创建数组对象,例9-5 (续),21,int main() unsigned n; cout n; vector arr(n); /创建数组对象 cout arri; cout “Average = “ average(arr) endl; return 0; ,9.2 用vector创建数组对象,22,9.3 深拷贝与浅拷贝,深拷贝与浅拷贝,浅拷贝 实现对象间数据元素的一一对应复制。 深拷贝 当被复制的对象数据成员是指针类型时,不是复制该指针成员本身,而是将指针所指对象进行复制。,例9-6(教材例6-21)对象的浅拷贝,23,#include #include using namespace std; class Point /类的声明同例6-16 / ; class ArrayOfPoints /类的声明同例6-18 / ;,9.3 深拷贝与浅拷贝,例9-6 (续),24,int main() int count; cout count; ArrayOfPoints pointsArray1(count); /创建对象数组 pointsArray1.element(0).move(5,10); pointsArray1.element(1).move(15,20); ArrayOfPoints pointsArray2 = pointsArray1; /创建副本 cout “Copy of pointsArray1:“ endl; cout “Point_0 of array2: “ pointsArray2.element(0).getX() “, “ pointsArray2.element(0).getY() endl; cout “Point_1 of array2: “ pointsArray2.element(1).getX() “, “ pointsArray2.element(1).getY() endl;,9.3 深拷贝与浅拷贝,例9-6 (续),25,pointsArray1.element(0).move(25, 30); pointsArray1.element(1).move(35, 40); cout “After the moving of pointsArray1:“ endl; cout “Point_0 of array2: “ pointsArray2.element(0).getX() “, “ pointsArray2.element(0).getY() endl; cout “Point_1 of array2: “ pointsArray2.element(1).getX() “, “ pointsArray2.element(1).getY() endl; return 0; ,9.3 深拷贝与浅拷贝,例9-6 (续),26,运行结果如下: Please enter the number of points:2 Default Constructor called. Default Constructor called. Copy of pointsArray1: Point_0 of array2: 5, 10 Point_1 of array2: 15, 20 After the moving of pointsArray1: Point_0 of array2: 25, 30 Point_1 of array2: 35, 40 Deleting. Destructor called. Destructor called. Deleting. 接下来程序出现异常,也就是运行错误。,9.3 深拷贝与浅拷贝,27,9.3 深拷贝与浅拷贝,拷贝前,拷贝后,例9-6 对象的深拷贝,28,#include #include using namespace std; class Point /类的声明同例6-16 ; class ArrayOfPoints public: ArrayOfPoints(const ArrayOfPoints int main() /同例6-20 ,9.3 深拷贝与浅拷贝,例9-6 (续),29,程序的运行结果如下: Please enter the number of points:2 Default Constructor called. Default Constructor called. Default Constructor called. Default Constructor called. Copy of pointsArray1: Point_0 of array2: 5, 10 Point_1 of array2: 15, 20 After the moving of pointsArray1: Point_0 of array2: 5, 10 Point_1 of array2: 15, 20 Deleting. Destructor called. Destructor called. Deleting. Destructor called. Destructor called.,9.3 深拷贝与浅拷贝,30,9.3 深拷贝与浅拷贝,拷贝前,拷贝后,指针与引用的对应关系,/使用指针常量 void swap(int * const pa, int * const pb) int temp = *pa; *pa = *pb; *pb = temp; int main() int a, b; swap( ,/使用引用 void swap(int ,31,9.4 深度探索 9.4.1 指针与引用,指针与引用的联系,引用在底层通过指针来实现 一个引用变量,通过存储被引用对象的地址,来标识它所引用的对象 引用是对指针的包装,比指针更高级 指针是C语言就有的底层概念,使用起来很灵活,但用不好容易出错 引用隐藏了指针的“地址”概念,不能直接对地址操作,比指针更安全,32,9.4 深度探索 9.4.1 指针与引用,引用与指针的选择,什么时候用引用? 如无需直接对地址进行操作,指针一般都可用引用代替 用更多的引用代替指针,更简洁、安全 什么时候用指针? 引用的功能没有指针强大,有时不得不用指针: 引用一经初始化,无法更改被引用对象,如有这种需求,必须用指针; 没有空引用,但有空指针,如果空指针有存在的必要,必须用指针; 函数指针; 用new动态创建的对象或数组,用指针存储其地址最自然; 函数调用时,以数组形式传递大量数据时,需要用指针作为参数。,33,9.4 深度探索 9.4.1 指针与引用,指针的地址安全性问题,地址安全性问题 通过指针,访问了不该访问的地址,就会出问题 典型问题:数组下标越界 问题的严重性:有时会在不知不觉中产生错误,错误源很难定位,因此程序调试起来很麻烦 解决方案 指针只有赋了初值才能使用(这一点普通变量也应遵循) 指针的算术运算,一定要限制在通过指向数组中某个元素的指针,得到指向同一个数组中另一个元素的指针 尽量使用封装的数组(如vector),而不直接对指针进行操作,34,9.4 深度探索 9.4.2 指针的安全性隐患及其应对方案,指针的类型安全性问题,基本类型数据的转换是基于内容的: 例: int i = 2; float x = static_cast(i); 目标类型不同的指针间的转换,会使一种类型数据的二进制序列被当作另一种类型的数据: reinterpret_cast:可以将一种类型的指针转换为另一种类型 int i = 2; float *p = reinterpret_cast( 结论 从一种具体类型指针转换为另一种具体类型指针的reinterpret_cast很不安全,一般情况下不要用,35,9.4 深度探索 9.4.2 指针的安全性隐患及其应对方案,指针的类型安全性问题(续),void指针与具体类型指针的转换: 具体类型指针可以隐含地转换为void指针: int i = 2; void *vp = 结论 void指针也容易带来不安全,尽量不用,在不得不用的时候,一定要在将void指针转换为具体类型指针时,确保指针被转换为它最初的类型。,36,9.4 深度探索 9.4.2 指针的安全性隐患及其应对方案,堆对象的管理,堆对象必须用delete删除 避免“内存泄漏” 原则很简单,但在复杂的程序中,一个堆对象常常要被多个不同的类、模块访问,该在哪里删除,常常引起混乱 如何有条理地管理堆对象 明确每个堆对象的归属 最理想的情况:在一个类的成员函数中创建的堆对象,也在这个类的成员函数中删除 把对象的建立和删除变成了一个类的局部问题 如需在不同类之间转移堆对象的归属,一定要在注释中注明,作为类的对外接口约定 例如在一个函数内创建堆对象并将其返回,则该对象应当由调用该函数的类负责删除,37,9.4 深度探索 9.4.2 指针的安全性隐患及其应对方案,const_cast的应用,const_cast的用法 用于将常指针、常引用转换为不带“const”的相关类型 例: void foo(const int *cp) int *p = const_cast(cp); (*p)+; 这可以通过常指针修改指针发对象的值,但这是不安全的用法,因为破坏了接口中const的约定 const_cast不是安全的转换,但有时可以安全地使用,38,9.4 深度探索 9.4.3 const_cast的应用,const_cast的安全使用,对例6-18的改进 例6-18通过下列函数访问数组元素 Point 新问题 代码的重复:这个element函数与原先的函数内容完全相同,两份重复的代码,不易维护,39,9.4 深度探索 9.4.3 const_cast的应用,const_cast的安全使用(续),新问题的解决 修改原先的element函数: Point 执行过程:调用常成员函数element(),再将其返回结果中的const用const_cast去除 将this用static_cast转换为常指针,是安全的转换 该函数本身不是常成员函数,确保将最终的结果以普通引用形式返回是安全的 思考:如果保留该函数,而修改常成员函数element,使常成员函数element调用该函数,是否合适?,40,9.4 深度探索 9.4.3 const_cast的应用,小结,41,9.5 小结,主要内容 动态存储分配、用vector创建数组对象、深拷贝与浅拷贝。 达到的目标 理解和掌握动态存储分配技术,会使用vector类,理解对象浅拷贝愈深拷贝的差别,会实现深拷贝。,

    注意事项

    本文(第9讲动态内存分配736304930.ppt)为本站会员(本田雅阁)主动上传,三一文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一文库(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    经营许可证编号:宁ICP备18001539号-1

    三一文库
    收起
    展开