7C++动态存储分配
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
异常相关语法
异常的抛出--throw – throw 表达式; 异常的检测和捕获--try-cacth – try –{ – 被检测可能产生异常的语句 –} – cacth(异常的类型) –{ – 异常处理语句 –} 处理思想:将异常处理和正常代码分开
int i; for(i = 0; i < _size; i++) { elems[i] = v.elems[i]; } }
2013-12-16
Vector::~Vector() { delete [] elems; }
//思考:是否应在析 构函数内代码增 加如下语句: if(elems == NULL) return;
18
几点说明
析构函数与类同名,无参数,无需指定返回值
析构函数不能有参数,因此不能重载
析构函数不能回收对象本身所占空间 如果不需要做清理工作,类可以没有析构函数 思考: – 在vector中,对象v1和v2能不能正确析构?? – 考虑对象的内存分布……
2013-12-16
19
对象的复制机制
2013-12-16
23
以下3种情况系统调用复制构造函数:
– 用类的一个对象初始化同类的另一个对
象时
– 对象作为函数参数传递给函数形参时 – 函数返回值是类的对象,函数调用完成
时返回
2013-12-16
24
异常
什么是异常 –异常是程序可能检测到的、运行时刻不正常的情况 –如:运行时刻数组下标越界、除0、空闲存储空间不
v1 5 3050 1 2 3 4 5 堆对象 hello
2013-12-16
v2 5Baidu Nhomakorabea
3050
Copy
3050
s 5
Copy
?
20
深复制、浅复制
s 堆对象 s 堆对象
浅 复 制
5
hello
Copy t 5
深 复 制
5
hello
Copy t 堆对象 hello 5
2013-12-16
当对象拥有资源时,C++提供复制构造函数实现深复制
基本类型一般不采用动态存储分配
7
2013-12-16
动态存储空间的回收
用new分配的空间一定要用delete回收 具体使用格式: – delete 指针变量名
– delete[] 指针变量名 //用于动态数组的内存回收 delete只能用于回收new所分配的空间 对于一个指针指向的堆对象只能执行一次 delete操作 delete[]忽略括符内的具体数字,无论是几维数 组的空间回收均只用一个括符表示
11
不足
程序仍然采用面向过程程序设计思想 – C语言中,数组没有自我意识,不知道自己的长度
、不能整体赋值、比较…… – 如果将数组设计为类Vector,可以在析构函数中完 成动态内存的释放、构造函数中完成数组的动态 内存申请
程序对于异常情况的处理可以采用异常机制, 将程序执行流向交由系统管理
12
序运行过程中,大小无法改变
– 动态数组在程序运行中,可根据需要重新指定大小 – 在构造函数中创建堆资源,析构函数中释放堆资源
测试代码中, Vector v4(v3);是否需要定义复制 15 构造函数?
class Vector { public: Vector(); Vector(int size, int value); Vector(const Vector &v); ~Vector(); void print() const; bool isEmpty() const; int length() const; int & at(int index); private: int _size; int *elems; };
重庆邮电大学计算机科学与技术学院 冯 潇
fengxiao@cqupt.edu.cn
主要内容
动态存储分配(难点) – 程序在内存中的分布 – new和delete运算符 – 复制构造函数——浅复制和深复制 – 析构函数 类模板
2013-12-16
我想这样定义数组
C语言允许我们定义静态的数组 – #define N 10 – int score[N]; 什么是静态数组? – 数组长度在编译时即定义好,在整个程序运行过
16
Vector::Vector() { _size = 0; elems = NULL; }
Vector::Vector(int size, int value) { if(size <= 0) { Vector::Vector(); return; } _size = size; elems = new int[size]; int i; for(i = 0; i < _size; i++) elems[i] = value; }
size
97 68 81 76 58
Code Segment Constant Segment Global Data Segment Heap Segment Stack Segment main dynamicalArray aver size 5
10
76
#include <iostream> #include <cstdlib> using namespace std;
程序运行时需要占用多大的空间需要在编译时确 定,便于操作系统为程序分配适当的内存空间。 从静态存储区分配:程序的全局变量和静态变量 都在这里分配,且在编译时已经分配好,在程序 终止前被操作系统回收。 在栈上创建:在函数调用时,函数的形参和局部 变量都在栈上创建,函数执行完毕时这些内存自 动被释放掉。 从堆(heap)上分配:在程序运行期间,用动态存 储分配函数申请和释放的内存
其他成员函数
– void print()、bool isEmpty()、int length()、?? at(int index)
– 请认真思考at的返回值类型?
14
难点
Vector 的数据成员包括数组长度和元素: – int SIZE;//数组当前元素个数 – int elems[n];??? 还是int *elems;??? – 内存映像图能否独立画出? 动态创建数组需要用到动态存储分配 – 静态数组指数组长度在编译时即定义好,在整个程
5
2013-12-16
动态存储分配
由动态内存管理系统管理的这块内存区域叫做 “堆(heap)”: – 当需要动态灵活地分配内存空间时,需要用到动
态存储分配
– 动态分配得到的内存块位于堆中,且没有名字
– 动态存储分配由库函数malloc.h提供 – 格式:p = (double* ) malloc(n*sizeof(double)) C++中动态存储分配由运算符new和delete实现 new和delete完成动态存储分配时,可以很好 地和构造函数、析构函数进行交互,malloc和 free不能自行调用构造函数和析构函数 2013-12-16
程中,数组大小无法改变
同学们经常想定义动态的数组 – 数组长度可以在程序运行起来后,由用户从键盘
指定
int size; cin >> size; 动态创建整型的score[size]
– 在程序运行过程中,可以根据实际需要,重新指
定数组大小
程序获得的内存分布
2013-12-16
4
程序中变量的内存分配方式
2013-12-16
8
说明以下定义的区别
a) int ival = 1024; b) int *pi = &ival; c) int *ip2 = new int(1024); d) int *ip3 = new int[1024];
2013-12-16
9
用动态数组统计全班的英语平均分
内存分配示意
2013-12-16
22
vector类的复制构造函数
vector::vector(const vector & v) { length = v.length; elems = new int[v.length]; for(i = 0 ; i < length; i++) elems[i] = v.GetElemsi[i]; }
6
动态存储空间的分配
具体方法: – 指针变量名 = new 类型;
– 指针变量名 = new 类型 (初值);
– 指针变量名 = new 类型 [元素个数]; 当执行new时,有两件事发生: – 大小适当的空间被分配给特定类型的变量; – 该存储空间首地址作为new表达式的返回值,若分
配失败则返回0 ;
int main() { Vector v1; //空的向量,无元素 Vector v2(5); //有5个元素的向量,每个元素值为0 Vector v3(5,9);//有5个元素的向量,每个元素值为9 v2.print(); v3.print(); v3.at(2) = 88; //等价于v3[2] = 88; v3.print(); cout << "v3[2] = " << v3.at(2) << endl; if(v1.isEmpty()) cout << "向量为空!" << endl; else cout << "向量不为空!" << endl; cout << "length of v2 is : " << v2.length() << endl; Vector v4(v3); v4.print(); return 0; }
够
异常处理 –异常处理应包含异常的检测、抛出和捕获 –具体而微的异常处理:从程序员角度增强程序的健
壮性和容错性
–系统层次的异常处理:从程序设计语言系统角度保
证程序的健壮性和容错性
C++异常处理机制
void main() { int x,y; cin>>x>>y; if(0 == y) { cout<<"除0错误!" <<endl; return; } cout<<x/y<<endl; } void main() { int x,y; cin>>x>>y; try//异常检测 { if(0 == y) throw 0;//抛出 cout<<x/y<<endl; } catch(int)//异常捕获 { cout<<"除数不能为0!" <<endl; } }
21
复制构造函数
主要功能 :
– 用一个已知的对象来初始化一个同类对象
具体声明格式: <类名>::<类名> (const <类名>& <对象名>) 复制构造函数只有一个参数,是该类对象的引用 若用户没有显式定义复制构造函数,编译器会自 动生成一个默认的复制构造函数,其功能是把已 知对象的每个数据成员都复制到新定义的对象中
int main() { int number; cout << "input the number of students: "; cin >> number; int *scores = new int[number]; if(scores == NULL) { cerr << "Out of heap space!" << endl; exit(EXIT_FAILURE); } int i; double aver = 0; for(i = 0;i < number;i++) { cout << "scores[" << i << "] = " ; cin >> scores[i]; aver += scores[i]; } aver /= number; delete[] scores; cout << "\naverage = " << aver << endl; return 0; }
17
Vector::Vector(const Vector &v) { _size = v._size; elems = new int[_size]; if(elems == NULL) { cerr << "Out of heap space!" << endl; exit(EXIT_FAILURE); }
测试驱动 开发
13
分析
Vector应采用动态存储形式实现
– Vector的数据成员有??
应提供3类构造函数
– Vector v1;
– Vector v2(n);
Vector::Vector()
Vector::Vector(int size)
– Vector v2(n,m); Vector::Vector(int size, int value)