刘胥影 liuxy@seu.edu.cn 东南大学计算机学院 面向对象程序设计1 2010~2011第3学期 刘胥影 liuxy@seu.edu.cn 东南大学计算机学院.

Slides:



Advertisements
Similar presentations
Oracle数据库 Oracle 子程序.
Advertisements

7.2 访问控制 —— 公有继承 公有继承练习 //Point.h #ifndef _POINT_H #define _POINT_H class Point { //基类Point类的定义 public: //公有函数成员 void initPoint(float x = 0, float.
第11章 异常处理 11.1 异常处理概述 11.2 异常处理的基本思想 11.3 C++异常处理的实现 11.4 标准C++库中的异常类
第14章 c++中的代码重用.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
C++程序设计 王希 图书馆三楼办公室.
Using C++ The Weird Way Something about c++11 & OOP tricks
Signutil.
資料大樓 --談指標與陣列 綠園.
刘胥影 东南大学计算机学院 面向对象程序设计1 2011~2012第3学期 刘胥影 东南大学计算机学院.
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
Object-Oriented Programming in C++ 第一章 C++的初步知识
第三章 C++中的C 面向对象程序设计(C++).
第12章 從C到C++語言 12-1 C++語言的基礎 12-2 C++語言的輸出與輸入 12-3 C++語言的動態記憶體配置
2 C++ 的基本語法和使用環境 親自撰寫和執行程式是學好程式語言的不二法門。本章藉由兩個簡單的程式,介紹C++ 程式的基本結構和開發環境,讓初學者能逐漸建立使用C++ 的信心。
Java语言程序设计 第五部分 Java异常处理.
第6章 异常的捕获及处理 6.1 异常简介 6.2 异常类的继承结构 6.3 异常处理机制 6.4 异常处理 6.5 本章小结.
第11讲 类的继承 1. 类的继承的概念 2. 类的单继承机制 3. 单继承中的构造函数和析构函数.
辅导课程六.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
Chapter 16 Exception Handling.
第5章 异常处理 王德俊 上海交通大学继续教育学院.
例外處理與 物件序列化(Exception Handling and Serialization of Objects)
刘胥影 东南大学计算机学院 面向对象程序设计1 2010~2011第3学期 刘胥影 东南大学计算机学院.
用event class 从input的root文件中,由DmpDataBuffer::ReadObject读取数据的问题
第七章 操作符重载 胡昊 南京大学计算机系软件所.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
第11讲 类的继承 1. 类的继承的概念 2. 类的单继承机制 3. 单继承中的构造函数和析构函数.
Chapter 2 & Chapter 3.
$9 泛型基础.
潘爱民 C++ Overview 潘爱民
程式結構&語法.
C#面向对象程序设计 $6 深入理解类.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
4 條件選擇 4.1 程式基本結構 循序式結構 選擇式結構 重複式結構 4-3
第7章 异常处理.
分裂对象模型 C++ otcl.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
Chap 5 函数 5.1 计算圆柱体积 5.2 使用函数编写程序 5.3 变量与函数.
第十章 异常处理   大型和十分复杂的程序往往会产生一些很难查找的甚至是无法避免的运行时错误。当发生运行时错误时,不能简单地结束程序运行,而是退回到任务的起点,指出错误,并由用户决定下一步工作。面向对象的异常处理(exception handling)机制是C++语言用以解决这个问题的有力工具。
第11章 從C到C++語言 11-1 C++語言的基礎 11-2 C++語言的資料型態與運算子 11-3 C++語言的輸出與輸入
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
本节内容 类成员的访问控制 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计教程 第2章 数据类型与表达式 第2章 数据类型与表达式 制作人:杨进才 沈显君.
第二章 Java语法基础.
面向对象技术 练习 ffh.
3.16 枚举算法及其程序实现 ——数组的作用.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第八章 继承 C++语言程序设计.
C/C++基礎程式設計班 C++: 物件的使用、參考、重載函式 講師:林業峻 CSIE, NTU 3/28, 2015.
#include <iostream.h>
第二章 Java基本语法 讲师:复凡.
第7章 模板 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
临界区问题的硬件指令解决方案 (Synchronization Hardware)
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第十一章 异常处理 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第八章 继承 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
第2章 Java语言基础.
第6章 异常处理 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第十一章 异常处理 C++语言程序设计.
變數與資料型態  綠園.
第二章 Java基础语法 北京传智播客教育
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
Presentation transcript:

刘胥影 liuxy@seu.edu.cn 东南大学计算机学院 面向对象程序设计1 2010~2011第3学期 刘胥影 liuxy@seu.edu.cn 东南大学计算机学院

Exception Handling 教学要求与安排 全部要求 东南大学计算机学院 1/17/2019

Exception Handling 16.1 异常处理简介 16.2 深入了解异常 异常对象 标准异常类 异常匹配 重新抛出异常 异常规格 (chap16.1, 16.2, 16.4, 16.13) (chap16.13) (chap16.10, 16.13) (chap16.5) (chap16.6, 16.7)

Exception Handling 16.3 几类异常处理 (chap16.14) 16.4 其他异常处理技术 栈展开 构造函数、析构函数和异常处理 动态内存分配的异常处理 16.4 其他异常处理技术 (chap16.8) (chap16.9) (chap16.11, chap16.12) (chap16.14)

异常处理简介 异常 异常处理 实例:处理除数为0的异常 异常处理的用处

异常 异常(Exception) 异常指示了程序在运行时出现了问题 e.g. 除数为0 int a = 1; int b = 0; cout<<a/b; 有未经处理的异常: Integer division by zero 东南大学计算机学院 1/17/2019

异常 常见的异常类型 除数为0 运算溢出 数组下标越界 无效的参数 内存分配失败 … … 东南大学计算机学院 1/17/2019

dynamic_cast运算符抛出的异常 标准异常 意料之外的异常 异常 仅在运行时才能检查到 运行前能检查到 运行时错误 逻辑错误 运算上溢错误 运算下溢错误 非法参数传递错误 长度超限错误 下标越界错误 运算符抛出的异常 new运算符抛出的异常 dynamic_cast运算符抛出的异常 typeid运算符抛出的异常 东南大学计算机学院 1/17/2019

异常处理 异常处理的步骤 抛出异常 侦测异常 处理异常 特别注意:抛出点必须在可能出错的语句之前 异常处理模式 :throw 抛出点 (throw point) :try :catch 异常处理模式 try { } 每个try块后面至少立即跟着一个catch处理器 可能出现异常的语句块 throw 可能出错的语句; 特定类型的异常; 定义异常类,描述问题, 在throw和catch间传递信息 继承标准库异常类 自定义 catch(特定类型的异常) { 处理异常; } 异常参数列表 catch(异常类类型 异常参数) 东南大学计算机学院 1/17/2019

异常处理 抛出多个异常 异常处理模式 每个try块后面至少立即跟着一个catch处理器 可能出现异常的语句块 { } catch(异常1) 处理异常1; 可能出现异常的语句块 throw 异常1; … … throw 异常2; catch(异常2) 处理异常2; 抛出多个异常 每个try块后面至少立即跟着一个catch处理器 catch处理器会匹配异常的类型 与抛出的异常类型相同 是抛出的异常的基类 东南大学计算机学院 1/17/2019

异常处理 异常类型匹配 抛出异常 的类型 catch处理器中 异常参数的类型 类型相同 抛出异常 的类型 catch处理器中 异常参数的类型 继承 基类的指针(引用)可以指向派生类的对象 东南大学计算机学院 1/17/2019

每个try块和相应的catch处理器间有代码是错误的 异常处理 try { … … throw 异常1; } 语句; //error catch(异常1) 处理异常1; try { … … throw 异常1; throw 异常2; } catch(异常1, 异常2) 处理异常1; 处理异常2; try { … … throw 异常1; throw 异常2; } catch(异常1) 处理异常1; 每个try块和相应的catch处理器间有代码是错误的 catch处理器只有一个参数(只能处理一种异常) 多个catch处理器捕获相同的异常是逻辑错误

异常处理 异常处理的终止模式 try语句块 catch处理器 throw 异常1 if … … throw 异常2 异常? 异常类型 true false … … throw 异常2 异常? 异常类型 catch(异常1){…} catch(异常2){…} 异常处理的终止模式 … … try { throw 异常1; throw 异常2; } catch(异常1) 处理异常1; catch(异常2) 处理异常2;

异常处理 若无异常 try语句块 catch处理器 throw 异常1 if … … throw 异常2 异常? 异常类型 true false … … throw 异常2 异常? 异常类型 catch(异常1){…} catch(异常2){…} 若无异常

异常处理 若抛出异常1 try语句块 catch处理器 throw 异常1 if … … throw 异常2 异常? 异常类型 true false … … throw 异常2 异常? 异常类型 catch(异常1){…} catch(异常2){…} 若抛出异常1

异常处理 若抛出异常2 try语句块 catch处理器 throw 异常1 if … … throw 异常2 异常? 异常类型 true false … … throw 异常2 异常? 异常类型 catch(异常1){…} catch(异常2){…} 若抛出异常2

dynamic_cast运算符抛出的异常 异常处理 回顾 标准异常类型 意料之外的异常 异常 运行时错误 逻辑错误 运算上溢出错误 运算下溢出错误 非法参数传递错误 长度超限错误 下标越界错误 运算符抛出的异常 new运算符抛出的异常 dynamic_cast运算符抛出的异常 typeid运算符抛出的异常 东南大学计算机学院 1/17/2019

dynamic_cast运算符抛出的异常 异常处理 标准库异常类层次 Exception bad_alloc bad_cast bad_type_id invalid_argument length_error out_of_range logic_error overflow_error underflow_error runtime_error bad_exception 运行时错误 逻辑错误 运算上溢错误 运算下溢错误 非法参数错误 长度超限错误 下标越界错误 new运算符抛出的异常 dynamic_cast运算符抛出的异常 typeid运算符抛出的异常 意料之外的异常 <exception> <stdexcept> <stdexcept> 东南大学计算机学院 1/17/2019

实例:处理除数为0的异常 double quotient(int numerator, int denominator){ if(denominator == 0) \\error,应抛出特定异常 return <static_cast>(numerator) / denominator; } main(){ int number1, number2; double result; cout << "Enter two integers (end-of-file to end): "; while(cin>>number1>>number2) { result = quotient(number1, number2); cout<< "The quotient is: " << result << endl; }

实例:处理除数为0的异常 异常处理第1步:抛出异常(throw) double quotient(int numerator, int denominator){ if(denominator == 0) \\error,应抛出特定异常 return static_cast <double>(numerator) / denominator; } throw DivideByZeroException(); 若throw的操作数为对象,称为异常对象 #include <stdexcept> using std::runtime_error; class DivideByZeroException : public runtime_error { public: DivideByZeroException() : runtime_error( "attempted to divide by zero" ) {} }; Fig. 16.1: DivideByZeroException.h 说明问题类型

实例:处理除数为0的异常 异常处理第2步:侦测异常(try) main(){ int number1, number2; double result; cout << "Enter two integers (end-of-file to end): "; while(cin>>number1>>number2) { result = quotient(number1, number2); cout<< "The quotient is: " << result << endl; } try { result = quotient(number1, number2); cout<< "The quotient is: " << result << endl; } 会出现异常的语句块 注意,不是对整个 while语句try 将cout语句包含进try,可保证quotient函数返回结果时才输出

实例:处理除数为0的异常 异常处理第3步:处理异常(catch) main(){ …… while(cin>>number1>>number2) { result = quotient(number1, number2); cout<< "The quotient is: " << result << endl; cout << "Enter two integers (end-of-file to end): "; } try { result = quotient(number1, number2); cout<< "The quotient is: " << result << endl; } throw DivideByZeroException(); catch( DivideByZeroException &divideByZeroException ) { cout << "Exception occurred: " << divideByZeroException.what() << endl; } exception类的virtual函数what(),返回异常的错误信息

实例:处理除数为0的异常 测试 Enter two integers (end-of-file to end): 100 7 The quotient is: 14.2857

     13 double quotient( int numerator, int denominator ) { 16 if ( denominator == 0 ) 17 throw DivideByZeroException(); 18 20 return static_cast< double >( numerator ) / denominator; 21 } 23 int main(){ 29 cout << "Enter two integers (end-of-file to end): "; 32 while ( cin >> number1 >> number2 ) 33 { 36 try 37 { 38 result = quotient( number1, number2 ); 39 cout << "The quotient is: " << result << endl; 40 } 43 catch ( DivideByZeroException &divideByZeroException ) 44 { 45 cout << "Exception occurred: " 46 << divideByZeroException.what() << endl; 47 } 49 cout << "\nEnter two integers (end-of-file to end): "; 50 } 52 cout << endl; 54 }     

实例:处理除数为0的异常 测试 Enter two integers (end-of-file to end): 100 7 The quotient is: 14.2857 Enter two integers (end-of-file to end): 100 0 Exception occurred: attempted to divide by zero class DivideByZeroException : public runtime_error { public: DivideByZeroException() : runtime_error( "attempted to divide by zero" ) {} };

        13 double quotient( int numerator, int denominator ) { 16 if ( denominator == 0 ) 17 throw DivideByZeroException(); 18 20 return static_cast< double >( numerator ) / denominator; 21 } 23 int main(){ 29 cout << "Enter two integers (end-of-file to end): "; 32 while ( cin >> number1 >> number2 ) 33 { 36 try 37 { 38 result = quotient( number1, number2 ); 39 cout << "The quotient is: " << result << endl; 40 } 43 catch ( DivideByZeroException &divideByZeroException ) 44 { 45 cout << "Exception occurred: " 46 << divideByZeroException.what() << endl; 47 } 49 cout << "\nEnter two integers (end-of-file to end): "; 50 } 52 cout << endl; 54 }        

内容回顾 异常 异常处理的三个步骤 异常匹配 标准库异常类的继承层次 抛出异常:throw 侦测异常:try 处理异常:catch 类型相同 throw的异常时catch异常形参的派生类 标准库异常类的继承层次 东南大学计算机学院 1/17/2019

异常处理的用处 何时使用异常处理? 异常处理的好处? 只能处理同步错误,不能处理异步事件 程序能在解决问题后继续执行(而不是直接终止) 除数为0 运算溢出 数组下标越界 无效的参数 内存分配失败 异常处理的好处? 只能处理同步错误,不能处理异步事件 异步事件:多个事件可以同时发生, 如:鼠标点击和键盘击键 程序能在解决问题后继续执行(而不是直接终止) 增强程序的健壮性 东南大学计算机学院 1/17/2019

深入了解异常处理 异常对象 标准库异常类 异常匹配 重新抛出异常 异常规格表

异常对象 异常对象 异常对象的生存期 异常对象不是局部对象 异常对象是由编译器管理的特殊对象,它驻留在可被激 活的任意catch处理器都能访问的空间 异常对象的生存期 创建:throw 撤销:在对应的catch中完全处理了异常后 东南大学计算机学院 1/17/2019

dynamic_cast运算符抛出的异常 标准库异常类 Exception bad_alloc bad_cast bad_type_id invalid_argument length_error out_of_range logic_error overflow_error underflow_error runtime_error bad_exception 运行时错误 逻辑错误 运算上溢错误 运算下溢错误 非法参数错误 长度超限错误 下标越界错误 new运算符抛出的异常 dynamic_cast运算符抛出的异常 typeid运算符抛出的异常 意料之外的异常 东南大学计算机学院 1/17/2019

标准库异常类 标准库异常类提供的操作 创建异常类对象 复制异常类对象 默认的赋值操作 exception、bad_alloc、bad_cast只定义了默认的构造函 数,无法在创建对象时提供初值 其他异常类只定义了一个使用string类初始化的构造函 数 exception类提供了virtual函数what(),返回C风格字符串 char *类型的错误信息 东南大学计算机学院 1/17/2019

标准库异常类 捕获所有潜在的异常 catch(…) catch(exception &)不能捕获所有异常,因为异常类可以 不继承exception类 东南大学计算机学院 1/17/2019

异常匹配 异常匹配规则 基类的指针可以指向派生类对象 可以利用多态性来处理异常 抛出异常 的类型 catch处理器中 异常参数的类型 类型相同 抛出异常 的类型 catch处理器中 异常参数的类型 继承 基类的指针可以指向派生类对象 可以利用多态性来处理异常 东南大学计算机学院 1/17/2019

异常匹配 异常匹配允许的类型转换 异常匹配不允许的类型转换 标准算术转换、自定义的类类型转换 抛出的异常 异常参数 派生类 基类 非const const 数组 数组指针 函数 函数指针 东南大学计算机学院 1/17/2019

异常匹配 异常匹配顺序 选择第一个可以处理该异常的catch处理器,而不必是 最佳匹配 存在函数调用链时,按函数执行顺序寻找匹配 void f(){ try { throw runtime_error(“runtime error"); } catch(logic_error &e) { cout<<"logic error"<<endl; } } int main(){ try{ f(); } catch(exception &e) { cout<<e.what()<<endl; } 函数f() 函数g() 函数k() 寻 找 异 常 匹 配 1/17/2019

异常匹配 异常与继承 可以在继承层次中定义异常类,通过基类指针指向不同派生类来统一处理异常 此时,不能访问派生类成员 bool flag = true; try { if(flag) throw runtime_error("runtime error"); else throw logic_error("logic error"); } catch(exception &e) { cout<<e.what()<<endl; } 此时,不能访问派生类成员 (基类指针只能访问基类成员) 1/17/2019

异常匹配 异常与继承 派生类的处理代码必须在基类的之前 bool flag = true; try { if(flag) throw runtime_error("runtime error"); else throw logic_error("logic error"); } catch(exception &e) { cout<<"Exception Handle: "<<e.what()<<endl; } catch(runtime_error &e) //不会执行 { cout<<"Runtime_error Handle: "<<e.what()<<endl; } 东南大学计算机学院 1/17/2019

异常匹配 异常与继承 派生类的处理代码必须在基类的之前 bool flag = true; try { if(flag) throw runtime_error("runtime error"); else throw logic_error("logic error"); } catch(runtime_error &e) { cout<<"Runtime_error Handle: "<<e.what()<<endl; } catch(exception &e) { cout<<"Exception Handle: "<<e.what()<<endl; } 东南大学计算机学院 1/17/2019

异常匹配 异常匹配不成功 异常没有经过try定义 没有catch处理器处理相应类型的异常 执行标准库函数terminate(),终止程序执行 ( <exception>头文件中定义) 通常情况下会导致程序非正常退出 异常没有经过try定义 没有catch处理器 执行标准库函数terminate() 东南大学计算机学院 1/17/2019

异常匹配 标准库函数terminate() 如果设置了set_terminate()函数,则调用其指定的函数 否则,调用abort函数,程序终止 不对自动对象和静态对象调用析构函数,导致内存泄漏 东南大学计算机学院 1/17/2019

重新抛出异常 为何要重新抛出异常(rethrow)? 重新抛出异常 需要在程序的不同部分对异常分别处理 异常处理器不能对异常进行完全处理 需要在多处对异常分别处理 重新抛出异常 需要在程序的不同部分对异常分别处理 通常存在多个函数调用时使用,使异常对象沿调用链向上传播 throw; 东南大学计算机学院 1/17/2019

重新抛出异常 调用函数 try { } 抛出的是原来的异常对象,而不是catch的形参 被调用函数 可能出现异常的语句块 特定类型的异常; throw 可能出错的语句; 特定类型的异常; runtime_error() catch(特定类型的异常) { 处理异常的语句1; } exception &e throw; runtime_error() catch(特定类型的异常) { } 处理异常的语句2; 1/17/2019

异常抛出表 异常抛出表(Exception Specifications) 列举了函数的一系列可以抛出的异常类型 void f() throw( ExceptionA, ExceptionB, ExceptionC ) { … … } 函数只可以抛出异常抛出表中列出的异常类型 东南大学计算机学院 1/17/2019

异常抛出表 异常抛出表 何时使用异常抛出表 可以抛出任何异常类型:不提供异常抛出表 不能抛出任何异常类型:throw( ) 若抛出的异常不在抛出表中,则调用unexpected()函数 (<exception>头文件中定义),该函数调用termination() 何时使用异常抛出表 一般情况下不建议使用 特殊情况:重写有抛出表的基类成员 东南大学计算机学院 1/17/2019

几种异常处理 栈展开 构造函数、析构函数和异常处理 动态内存分配的异常处理

栈展开 栈展开(Stack Unwinding) 栈:函数调用栈 throw 抛出异常 try 侦测异常 catch 处理异常 { throw 异常; } catch(异常) … … 标准异常处理模式 当存在函数调用时,标准模式不能满足需要,情况变的复杂 1/17/2019

栈展开 try/catch均不在本函数内 标准模式 相应的catch不在本函数内 void f(){ try { throw 异常1; } … … int main(){ f(); void f(){ try { throw 异常1; } catch(异常2) {… …} int main(){ f(); catch(异常1) void f(){ throw 异常1; } int main(){ try { f(); catch(异常1) … … try/catch均不在本函数内 标准模式 相应的catch不在本函数内 1/17/2019

栈展开 回顾:存在函数调用链时的异常匹配顺序 void f(){ try { throw runtime_error(“runtime error"); } catch(logic_error &e) { cout<<"logic error"<<endl; } } int main(){ try{ f(); } catch(exception &e) { cout<<e.what()<<endl; } 函数f() 函数g() 函数k() 寻 找 异 常 匹 配 东南大学计算机学院 1/17/2019

栈展开 栈展开(Stack Unwinding) 当被调用函数中抛出异常,但没有用try-catch将其捕获,则展开函数调用栈,沿函数执行顺序在调用函数内寻找try-catch块捕获该异常 void f(){ throw runtime_error(“runtime error"); } } int main(){ try{ f(); } catch( exception &e ) { cout<<e.what()<<endl; } 函数f() 函数g() 函数k() 捕 获 异 常 顺 序 1/17/2019

栈展开 抛出异常时的程序执行 抛出异常时,立即中断该函数的执行,查找匹配的catch处理器对异常进行处理 throw 抛出异常 try 侦测异常 catch 处理异常 中断函数执行 查找try 查找catch 异常匹配 东南大学计算机学院 1/17/2019

栈展开 抛出异常时的程序执行 中断函数执行 查找try 查找catch 不需要查找 需要查找 throw在try内 throw不在try内 void f(){ try { throw … …; } catch(…) {… …} void f(){ throw … …; } int main(){ try { f(); catch(…) {… …} 东南大学计算机学院 1/17/2019

栈展开 throw在try内 中断函数执行 查找try 查找catch 中断函数执行 查找catch 不匹配 退出当前程序 返回调用函数 匹配 执行catch处理器 释放当前函数的内存,并撤销局部对象 执行catch后的第一条语句 东南大学计算机学院 1/17/2019

栈展开 throw在try内 中断函数执行,判断throw在catch内 查找当前try对应的catch:不匹配 退出当前函数f() void f(){ try { throw 异常1; } catch(异常2) {… …} 语句1; int main(){ f(); catch(异常1) catch(其他异常){……} 语句2; 中断函数执行,判断throw在catch内 查找当前try对应的catch:不匹配 查找当前try对应的catch:匹配 退出当前函数f() 返回调用函数main() 执行catch处理器 执行catch后的第一条语句

栈展开 throw不在try内 中断函数执行 查找try 查找catch 退出当前函数,沿函数调用链上行,找到第一个try main() void g(){ throw 异常1; } void f(){ try { g(); catch(异常2) {… …} 语句1; int main(){ try { f(); } catch(异常1) {… …} catch(其他异常){……} 语句2; main() f() g() 捕 获 异 常 顺 序 东南大学计算机学院 1/17/2019

构造函数、析构函数和异常处理 构造函数抛出异常 该对象只是部分被构造  对象不完整 对try中已构造的自动对象调用析构函数 若自动对象包含成员对象,则成员对象的析构函数将会 被调用 若自动对象为数组对象,且异常发生时,数组对象只是 部分被构造,那么,数组中已经完成构造的对象才会被 析构 东南大学计算机学院 1/17/2019

构造函数、析构函数和异常处理 析构函数抛出异常 若析构函数抛出异常 析构函数释放资源,一般不会抛出异常 标准库类型保证其析构函数不会抛出异常 栈展开期间经常会调用析构函数,在处理异常时,又遇 到析构函数的异常 调用terminate函数 调用set_unexpected函数指定的函数 abort 析构函数释放资源,一般不会抛出异常 标准库类型保证其析构函数不会抛出异常 东南大学计算机学院 1/17/2019

动态内存分配的异常处理 new:分配内存 delete:释放内存 异常: 无法分配内存:new运算符,内存已满 东南大学计算机学院 1/17/2019

动态内存分配的异常处理 new失败 抛出bad_alloc异常(<new>头文件中定义) double *ptr[50]; try { for(int i=0; i<50; i++) ptr[i] = new double[50000000]; } catch( bad_alloc &e) cerr << e.what(); 内存不足时,new运算符函数抛出bad_alloc异常 bad allocation 使用catch处理器处理异常 东南大学计算机学院 1/17/2019

动态内存分配的异常处理 new失败的处理 使用set_new_handler(<new>头文件中定义) 不直接抛出bad_alloc异常,使用new处理器处理 new处理器的选择: 1. 释放其他动态分配的内存,并返回 new,尝试再次分配内存 2. 抛出bad_alloc异常 3. 调用abort或exit结束程序 东南大学计算机学院 1/17/2019

动态内存分配的异常处理 没有抛出异常:不需要throw-try-catch异常处理机制 double *ptr[50]; set_new_handler( customNewHandler ); for(int i=0; i<50; i++) { ptr[i] = new double[50000000]; } void customNewHandler() { cerr<< “customNewHandler was called”; abort(); } 没有抛出异常:不需要throw-try-catch异常处理机制 东南大学计算机学院 1/17/2019

动态内存分配的异常处理 new运算符总结 new成功分配内存:返回指向内存的指针 new分配内存失败: set_new_handler没有注册new处理器函数: 抛出bad_alloc异常 set_new_handler注册了new处理器函数: 调用new处理器 东南大学计算机学院 1/17/2019

动态内存分配的异常处理 异常 内存泄漏 局部自动变量总是会被销毁的 new分配内存 delete释放内存 内存泄漏 动态对象生命期 局部自动变量总是会被销毁的 auto_ptr类模板 局部自动对象 动态对象 … 指针成员 析构函数:delete指针成员指向的动态对象 当局部自动对象退出其作用域时销毁,其析构函数指示销毁其管理的动态对象,则会调用动态对象的析构函数

动态内存分配的异常处理 类模板auto_ptr (<memory>头文件中定义) 当一个auto_ptr类对象的析构函数被调用时,将delete其指针数据成员 局部自动对象 动态对象 … 指针成员 析构函数:delete指针成员指向的动态对象 东南大学计算机学院 1/17/2019

动态内存分配的异常处理 int main(){ auto_ptr<Integer> p( new Integer(7)); p->setInteger(9); cout << p->getInteger(); } class Integer{ public: Integer(int i=0); ~Integer(); void setInteger(int); int getInteger(); private: int value; }; p是main函数中的局部自动变量,在main结束时被销毁,其析构函数所指向的Integer对象被delete,此时,调用Integer对象的析构函数。 东南大学计算机学院 1/17/2019

其他异常处理技术

其他异常处理技术 忽视异常:一般用于为个人目的设计的程序 中断程序:经常使用 设置错误指示器:main函数 测试错误条件,传递错误信息,调用exit函数:经常使用 设置专门的函数处理:set_new_handler 东南大学计算机学院 1/17/2019

Exception Handling 教学要求与安排 全部要求 东南大学计算机学院 1/17/2019

作业 deadline: 5.31 24:00 H10:Ex. 16.25, 16.26, 16.35, 16.36 东南大学计算机学院 1/17/2019