Chapter 16 Exception Handling.

Slides:



Advertisements
Similar presentations
C++语言程序设计教程 第5章 构造数据类型 第6章 C++程序的结构.
Advertisements

移动应用软件开发技术 第二讲:C++编程基础
Oracle数据库 Oracle 子程序.
第4章 数组 数组是由一定数目的同类元素顺序排列而成的结构类型数据 一个数组在内存占有一片连续的存储区域 数组名是存储空间的首地址
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++中的代码重用.
Data Abstraction: The Walls
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
Using C++ The Weird Way Something about c++11 & OOP tricks
EBNF与操作语义 请用扩展的 BNF 描述 javascript语言里语句的结构;并用操作语义的方法描述对应的语义规则
Chapter 1 用VC++撰寫程式 Text book: Ivor Horton.
例外處理(Exception Handling)
Derived Class 前言 衍生類別的定義 單一繼承 public, protected, 和 privated 基底類別
EBNF 请用扩展的 BNF 描述 C语言里语句的结构; 请用扩展的 BNF 描述 C++语言里类声明的结构;
刘胥影 东南大学计算机学院 面向对象程序设计1 2011~2012第3学期 刘胥影 东南大学计算机学院.
Scope & Lifetime 前言 Local Scope Global Functions & Objects
刘胥影 东南大学计算机学院 面向对象程序设计1 2011~2012第3学期 刘胥影 东南大学计算机学院.
Classes: A Deeper Look, Part 1
刘胥影 东南大学计算机学院 面向对象程序设计1 2010~2011第3学期 刘胥影 东南大学计算机学院.
Object-Oriented Programming:
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
2 C++ 的基本語法和使用環境 親自撰寫和執行程式是學好程式語言的不二法門。本章藉由兩個簡單的程式,介紹C++ 程式的基本結構和開發環境,讓初學者能逐漸建立使用C++ 的信心。
第6章 异常的捕获及处理 6.1 异常简介 6.2 异常类的继承结构 6.3 异常处理机制 6.4 异常处理 6.5 本章小结.
辅导课程六.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
刘胥影 东南大学计算机学院 面向对象程序设计1 2010~2011第3学期 刘胥影 东南大学计算机学院.
刘胥影 东南大学计算机学院 面向对象程序设计1 2010~2011第3学期 刘胥影 东南大学计算机学院.
第二章 Java语言基础.
用event class 从input的root文件中,由DmpDataBuffer::ReadObject读取数据的问题
第七章 操作符重载 胡昊 南京大学计算机系软件所.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
1.3 C语言的语句和关键字 一、C语言的语句 与其它高级语言一样,C语言也是利用函数体中的可执行 语句,向计算机系统发出操作命令。按照语句功能或构成的不 同,可将C语言的语句分为五类。 goto, return.
EBNF与操作语义 请用扩展的 BNF 描述 javascript语言里语句的结构;并用操作语义的方法描述对应的语义规则
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
Chapter 2 & Chapter 3.
$9 泛型基础.
潘爱民 C++ Overview 潘爱民
Speaker: Liu Yu-Jiun Date: 2009/4/29
C#面向对象程序设计 $6 深入理解类.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
Aspect Oriented Programming
分裂对象模型 C++ otcl.
第12章 异常处理 C++自身有着非常强的纠错能力,发展到如今,已经建立了比较完善的异常处理机制. C++的异常情况无非两种,一种是语法错误,即程序中出现了错误的语句、函数结构和类,致使编译程序无法进行。另一种是运行时发生的错误,一般与算法有关。 关于语法错误, C++编译器的报错机制可以让我们轻松地解决这些错误;
第十章 异常处理   大型和十分复杂的程序往往会产生一些很难查找的甚至是无法避免的运行时错误。当发生运行时错误时,不能简单地结束程序运行,而是退回到任务的起点,指出错误,并由用户决定下一步工作。面向对象的异常处理(exception handling)机制是C++语言用以解决这个问题的有力工具。
Inheritance -II.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
第4章 Excel电子表格制作软件 4.4 函数(一).
面向对象技术 练习 ffh.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第八章 继承 C++语言程序设计.
辅导课程十五.
#include <iostream.h>
第7章 模板 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
本节内容 C语言的汇编表示 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第十一章 异常处理 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第八章 继承 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
3.7 Java的异常处理机制.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
C++面向对象程序设计 谭浩强编著 授课教师:姬广永 学习网站:
第6章 异常处理 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第十一章 异常处理 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
資料結構與C++程式設計進階 C++與資料結構 講師:林業峻 CSIE, NTU 7/ 5, 2010.
第1章 C++程序设计基础 网络游戏开发-C++程序设计.
Presentation transcript:

Chapter 16 Exception Handling

OBJECTIVES What exceptions are and when to use them. To use Try, catch and throw to detect, handle and indicate exceptions, respectively. To process uncaught and unexpected exceptions. To declare new exception classes. How stack unwinding enables exceptions not caught in one scope to be caught in another scope. To handle new failures. To use auto_ptr to prevent memory leaks. To understand the standard exception hierarchy.

Topics 16.1 Introduction 16.2 Exception-Handling Overview 16.3 Example: Handling an Attempt to Divide by Zero 16.4 When to Use Exception Handling 16.5 Rethrowing an Exception 16.6 Exception Specifications 16.7 Processing Unexpected Exceptions 16.8 Stack Unwinding 16.9 Constructors, Destructors and Exception Handling 16.10 Exceptions and Inheritance 16.11 Processing new Failures

16.1 Introduction 大型程序往往会产生一些很难查找的甚至是无法避免的运行时错误。 当发生运行时错误时,不能简单地结束程序运行,而是需要指出错误,并由用户决定下一步工作。面向对象的异常处理(exception handling)机制是C++语言用以解决这个问题的有力工具。

16.1 Introduction 异常(exception)是程序可能检测到的,运行时不正常的情况,如存储空间耗尽、数组越界、被0除等等。 特点:可以预见可能发生在什么地方,但是无法确知怎样发生和何时发生。 在一个大型的程序(软件)中,程序各部分是由不同的小组编写的,它们由公共接口连起来,错误可能就发生在相互的配合上,也可能发生在事先根本想不到的个别的条件组合上。

Topics 16.1 Introduction 16.2 Exception-Handling Overview 16.3 Example: Handling an Attempt to Divide by Zero 16.4 When to Use Exception Handling 16.5 Rethrowing an Exception 16.6 Exception Specifications 16.7 Processing Unexpected Exceptions 16.8 Stack Unwinding 16.9 Constructors, Destructors and Exception Handling 16.10 Exceptions and Inheritance 16.11 Processing new Failures

16.2 Exception-Handling Overview //直观的错误处理模式 Perform a task If the preceding task did not execute correctly Perform error processing else Perform next task 将程序逻辑和错误处理逻辑混合,降低程序性能。 C++提供了异常处理模式!---将异常处理单独分离

16.2 Exception-Handling Overview 解决思路:C++提供了一些内置的语言特性来抛出(throw)异常,用以通知“异常已经发生”,然后由预先安排的程序段来捕获(catch)异常,并对它进行处理。 //捕获并处理异常的程序段 try {复合语句} catch(异常类型声明1) catch(异常类型声明2) … //抛掷异常的程序段 ...... throw 表达式; 多个

16.2 Exception-Handling Overview --流程解释 将可能抛出异常的程序段嵌在try块之中,并通过throw操作创建一个异常对象并抛掷。 如果此时没有引起异常,程序从try块后跟随的最后一个catch子句后面的语句继续执行下去。 如果存在异常,顺序检查try块后面的catch子句,匹配的catch子句将捕获并处理异常(或继续抛掷异常)。 如果匹配的处理器未找到,则默认调用terminate函数,其缺省功能是调用abort终止程序。(具体在16.7节中阐述)

Topics 16.1 Introduction 16.2 Exception-Handling Overview 16.3 Example: Handling an Attempt to Divide by Zero 16.4 When to Use Exception Handling 16.5 Rethrowing an Exception 16.6 Exception Specifications 16.7 Processing Unexpected Exceptions 16.8 Stack Unwinding 16.9 Constructors, Destructors and Exception Handling 16.10 Exceptions and Inheritance 16.11 Processing new Failures

例:处理除零异常 程序运行结果如下: 5/2=2 except of deviding zero. that is ok. 抛出的是整数类型 #include<iostream> int Div(int x,int y); int main() { try { cout<<"5/2="<<Div(5,2)<<endl; cout<<"8/0="<<Div(8,0)<<endl; cout<<"7/1="<<Div(7,1)<<endl; } catch(int) { cout<<"except of deviding zero.\n"; } cout<<"that is ok.\n"; int Div(int x,int y) { if(y==0) throw y; return x/y; 程序运行结果如下: 5/2=2 except of deviding zero. that is ok. 抛出的是整数类型

16.3 Example: Handling an Attempt to Divide by Zero 抛出的异常可以是任何类型的对象,如枚举、整 数等等。但最常用的是类对象。 异常类——都派生自exception类(最高级)

16.3 Example: Handling an Attempt to Divide by Zero(抛出异常类对象的模式) #include <stdexcept> using std::runtime_error; Class DivideByZeroException : public runtime_error {public: DivideByZeroException() : runtime_error( "attempted to divide by zero" ) {} }; 程序解读 16.1~2

异常类层次结构 C++标准库提供的逻辑异常: C++标准库提供的运行时异常() 2019年1月1日8时24分 异常类层次结构 C++标准库提供的逻辑异常: invalid_argument异常,接收到一个无效的实参,抛出该异常。 out_of_range异常,收到一个不在预期范围中的实参,则抛出。 length_error异常,报告企图产生“长度值超出最大允许值”的对象 domain_error异常,用以报告域错误(domain error)。 C++标准库提供的运行时异常() range_error异常,报告内部计算中的范围错误。 overflow_error异常,报告算术溢出错误。 underflow_error异常,报告算术下溢错误。 以上三个异常是由runtime_error类派生的。 bad_alloc异常。当new()操作符不能分配所要求的存储区时,会抛出该异常。它是由基类exception派生的。 short int  val=32767; //加一 发生overflow (overflow 后结果:-32768) val  = val + 1; //val减一,发生underflow(underflow后结果:32767) val  = val -1; bad_alloc:全局操作符new失败。 bad_cast:加诸于reference上的“动态型别转换操作”失败,如dynamic_cast操作失败。 bad_typeid:执行期型别辨识时,typeid操作符的参数为0或空指针。 bad_exception:发生非预期异常,由bad_exception异常调用unexpected()接手处理。

<exception> exception类的接口如下: namespace std{ //注意在名字空间域std中 class exception{ public: exception() throw() ; //默认构造函数 exception(const exception &) throw() ; //复制构造函数 exception &operator=(const exception&) throw() ; //复制赋值操作符 virtual ~exception() throw() ; //析构函数 virtual const char* what() const throw() ; //返回一个C风格的字符串,目的是为抛出的异常提供文本描述 }; }

runtime_error:<stdexcept> 2019年1月1日8时24分 runtime_error:<stdexcept> exception<——runtime_error This class defines the type of objects thrown as exceptions to report errors that can only be determined during runtime. class runtime_error : public exception { public: explicit runtime_error (const string& what_arg); }; 在C++中,explicit关键字用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换。

创建一个临时异常对象 打印异常错误信息 double quotient (int numerator, int denominator ){ if (denominator == 0) throw DivideByZeroException(); return static_cast<double>(numerator)/denominator; } int main(){ int number1,number2; double result; while (cin>>number1>>number2){ try{ result = quotient(number1,number2); catch (DivideByZeroException & divideByZeroException){ cout<<“Exception occurred:” << divideByZeroException.what()<<endl; 打印异常错误信息

16.2 Exception-Handling Overview -- try、throw子句 try语句中包含可能引起异常的语句和在异常发生时应该跳过的语句(如numerator /denominator) 异常可能在try语句块的代码中,也可能出现在try语句中其它函数的调用和深层嵌套的函数调用中

16.2 Exception-Handling Overview -- catch子句 2019年1月1日8时24分 16.2 Exception-Handling Overview -- catch子句 catch子句由三部分组成:关键字catch、圆括号中的异常声明以及复合语句中的一组语句。 catch子句不是函数,所以圆括号中不是形参,而是一个异常类型声明,可以是类型也可以是对象。 catch子句的使用:由系统按抛出的异常类型自动在catch子句列表中匹配(找寻能够处理的第一个catch处理器)。(类型相同或是继承类) catch子句可以包含返回语句(return),也可不包含返回语句。包含返回语句,则整个程序结束。不包含返回语句,则执行最后一个catch处理器之后的下一条语句(不会回到异常发生点)。 如果没有异常发生,继续执行try块中的代码,与try块相关联的catch子句被忽略,程序正常执行 为什么要区分的那么清楚和函数之间的区别?

注意: try与catch间不能添加其他代码 一个catch处理器只能有一个参数 2019年1月1日8时24分 注意: try与catch间不能添加其他代码 一个catch处理器只能有一个参数 在try语句后两个不同catch处理器中捕获相同异常类型——错误! 通过引用捕获异常对象,能够去除表示抛出的异常对象的复制开销 如果是基类和派生类的对象分别为两个Catch字句的类型,如何?

Topics 16.1 Introduction 16.2 Exception-Handling Overview 16.3 Example: Handling an Attempt to Divide by Zero 16.4 When to Use Exception Handling 16.5 Rethrowing an Exception 16.6 Exception Specifications 16.7 Processing Unexpected Exceptions 16.8 Stack Unwinding 16.9 Constructors, Destructors and Exception Handling 16.10 Exceptions and Inheritance 16.11 Processing new Failures

16.4 When to Use Exception Handling 异常处理应当只用于异常情况 程序本身的局部错误可用传统控制方法 处理库函数产生的错误时通常用异常 例如: 数组下标越界 运算溢出 除数为0 无效的函数参数 失败的内存分配

Topics 16.1 Introduction 16.2 Exception-Handling Overview 16.3 Example: Handling an Attempt to Divide by Zero 16.4 When to Use Exception Handling 16.5 Rethrowing an Exception 16.6 Exception Specifications 16.7 Processing Unexpected Exceptions 16.8 Stack Unwinding 16.9 Constructors, Destructors and Exception Handling 16.10 Exceptions and Inheritance 16.11 Processing new Failures

16.5 Rethrowing an Exception 当catch语句捕获一个异常后,可能无法处理或不能完全处理异常,完成某些操作后,该异常必须由函数链中更上级(更外层)的函数来处理,这时catch子句可以重新抛出(throw;)该异常,把异常传递给函数调用链中更上级的另一个catch子句,由它进行进一步处理。 throw;//异常的再抛出 由其外层的catch捕获 外层无catch处理器时,编译器调用terminate终止程序 程序解读 P 16.3

Topics 16.1 Introduction 16.2 Exception-Handling Overview 16.3 Example: Handling an Attempt to Divide by Zero 16.4 When to Use Exception Handling 16.5 Rethrowing an Exception 16.6 Exception Specifications 16.7 Processing Unexpected Exceptions 16.8 Stack Unwinding 16.9 Constructors, Destructors and Exception Handling 16.10 Exceptions and Inheritance 16.11 Processing new Failures

16.6 Exception Specifications(异常指定或异常规范) 2019年1月1日8时24分 16.6 Exception Specifications(异常指定或异常规范) int someFunction( double value ) throw (a, b, c) { // function body } 异常指定:列出函数可抛出的异常 函数可抛出指定异常或派生类型 当函数抛出异常不在异常指定中,调用C++标准库的unexpected函数 不带异常指定的函数可以抛出任何异常 void g(); 如果异常指定为throw(),表示该函数不抛出异常。 抛出一个函数异常规格中未声明的异常或者包括空异常规格下抛出异常,将由unexpected()处理 Unexpected()与terminate()

16.6 Exception Specifications(异常指定) 2019年1月1日8时24分 16.6 Exception Specifications(异常指定) 虚函数中的异常指定: 派生类的虚函数的异常指定必须与基类虚函数的异常一样或更严格。因为当派生类的虚函数被指向基类类型的指针调用时,保证不会违背基类成员函数的异常规范。 class CBase{ public: virtual int fun1(int) throw(); virtual int fun2(int) throw(int); virtual string fun3() throw(int,string);}; class CDerived:public CBase{ int fun1(int) throw(int); //错!异常规范不如throw()严格 int fun2(int) throw(int); //对!有相同的异常规范 string fun3() throw(string); } //对!异常规范比 throw(int,string)更严格 ???

Topics 16.1 Introduction 16.2 Exception-Handling Overview 16.3 Example: Handling an Attempt to Divide by Zero 16.4 When to Use Exception Handling 16.5 Rethrowing an Exception 16.6 Exception Specifications 16.7 Processing Unexpected Exceptions 16.8 Stack Unwinding 16.9 Constructors, Destructors and Exception Handling 16.10 Exceptions and Inheritance 16.11 Processing new Failures

16.7 Processing Unexpected Exceptions unexpected()调用set_unexpected() 指定的函数 set_unexpected 定义在<exception> 如果set_unexpected() 未指定被调用函数,默认情况下,terminate()被调用 terminate定义在<terminate> terminate()调用set_terminate()指定的函数 如果set_terminate()未指定被调用函数,默认调用abort(),退出程序,不会释放内存,导致资源泄漏 函数set_terminate和set_unexpected取函数指针为参数。每个参数指向返回类型为void和无参数的函数。

另一个例子 #include <iostream> #include <exception> using namespace std; void myterminate() { cerr << "terminate called\n"; } void myfunction () { throw 'x';} int main (void) { set_terminate (myterminate); try { myfunction(); } catch (int) { cerr << "caught int\n"; } catch (...) { cerr << "caught other exception (non-compliant compiler?)\n"; } return 0; } catch (...)表示可以接受任何类型的异常

catch(...){ /*代码*/ } // catch_all子句 2019年1月1日8时24分 catch(...){ /*代码*/ } // catch_all子句 任何异常都可以进入这个catch子句。这里的三个点称为省略号。花括号中的复合语句用来执行指定操作。 catch_all子句可以单独使用,也可以与其它catch子句联合使用。如果联合使用,它必须放在相关catch子句表的最后。 如果catch_all子句放在前面进行某项操作,则其它的操作应由catch子句重新抛出异常,逆调用链去查找新的处理子句来处理。 异常发生后按栈展开(stack unwinding)退出,动态分配的非类对象资源不会自动释放的,通常在catch_all子句中释放。

res=new int[100]; //定义一个资源对象 try{ //代码包括使用资源res和某些可能引起异常抛出的操作 2019年1月1日8时24分 void fun1(){ int *res; res=new int[100]; //定义一个资源对象 try{ //代码包括使用资源res和某些可能引起异常抛出的操作 } //异常可能有多种 catch(...){ //不论是那种异常都在此释放 delete [] res; //释放资源对象res throw; }//重新抛出异常 delete [] res; } //正常退出前释放资源对象res;

Topics 16.1 Introduction 16.2 Exception-Handling Overview 16.3 Example: Handling an Attempt to Divide by Zero 16.4 When to Use Exception Handling 16.5 Rethrowing an Exception 16.6 Exception Specifications 16.7 Processing Unexpected Exceptions 16.8 Stack Unwinding 16.9 Constructors, Destructors and Exception Handling 16.10 Exceptions and Inheritance 16.11 Processing new Failures

16.8 Stack Unwinding 栈展开(stack unwinding):因发生异常而逐步退出复合语句和函数定义的过程。 2019年1月1日8时24分 16.8 Stack Unwinding 栈展开(stack unwinding):因发生异常而逐步退出复合语句和函数定义的过程。 具体过程: 当异常被抛出但没有在特定的域内被捕获时,该函数调用堆栈将展开,并试图在下一个外部try-catch语句中处理 展开函数调用堆栈意味着在调用链中没有捕获异常的函数将会终止执行,并控制返回到最初调用该函数的语句中 如果该调用语句被一个try语句包含,则试图捕获该异常;否则堆栈展开将继续发生 如果在main函数中仍没有找到匹配的Handler, 则调用terminate函数(该函数缺省调用abort, 不执行栈展开), 结束程序. 1:在C++异常机制中,代码控制流会从throw语句跳转到第一个可以处理这种异常的catch语句的地方,在达到这样的catch语句时,所有位于引发异常和这个catch语句之间的作用域范围内的(即能够处理这个异常的try-catch结构中try起始处到引发异常的throw语句之间)已经构造好的局部变量都会被销毁(如果是对象,对应的析构函数就会被调用),这个过程就是栈展开。 2:抛出异常时,将暂停当前函数的执行,开始查找匹配的catch子句。首先检查throw本身是否在try块内部,如果是,检查与该try相关的catch子句,看是否可以处理该异常。如果不能处理,就退出当前函数,并且释放当前函数的内存并销毁局部对象,继续到上层的调用函数中查找,直到找到一个可以处理该异常的catch。这个过程称为栈展开(stack unwinding)。当处理该异常的catch结束之后,紧接着该catch之后的点继续执行。

注意! 在栈展开期间,在退出的域中有某个局部量是类对象,栈展开过程将自动调用该对象的析构函数,完成资源的释放。

16.8 Stack Unwinding ③ ② ① fun1 is called inside main Constructor 1 1. void function3() throw ( runtime_error ) 2. { 3. cout << "In fun3\n"; 4. Test t(3); 5. throw runtime_error( "runtime_error in fun3" ); 6. cout << "Reach here? fun3\n"; 7.} 1. int main() 2. { 3. try { 4. cout << "fun1 is called inside main\n"; 5. function1(); 6. cout << "Reach here? fun main\n"; 7. } 8. catch ( runtime_error &error ) { 9. cout << "Exception occurred: " 10. << error.what() << endl; 11. cout << "Exception handled in main\n"; 12. } 13. return 0; 14. } ③ 1. void function2() throw ( runtime_error ) 2. { 3. Test t(2); 4. cout << "fun3 is called inside fun2\n"; 5. function3(); 6. cout << "Reach here? fun2\n"; 7. } ② ① fun1 is called inside main Constructor 1 fun2 is called inside fun1 Constructor 2 fun3 is called inside fun2 In fun3 Constructor 3 1. void function1() throw ( runtime_error ) 2. { 3. Test t(1); 4. cout << "fun2 is called inside fun1\n" ; 5. function2(); 6. cout << "Reach here? Fun1\n"; 7. }

16.8 Stack Unwinding ④ ⑦ ⑧ ⑤ ⑥ Destructor 3 Destructor 2 Destructor 1 1. void function3() throw ( runtime_error ) 2. { 3. cout << "In fun3\n"; 4. Test t(3); 5. throw runtime_error( "runtime_error in fun3" ); 6. cout << "Reach here? fun3\n"; 7.} 1. int main() 2. { 3. try { 4. cout << "fun1 is called inside main\n"; 5. function1(); 6. cout << "Reach here? fun main\n"; 7. } 8. catch ( runtime_error &error ) { 9. cout << "Exception occurred: " 10. << error.what() << endl; 11. cout << "Exception handled in main\n"; 12. } 13. return 0; 14. } ④ ⑦ 1. void function2() throw ( runtime_error ) 2. { 3. Test t(2); 4. cout << "fun3 is called inside fun2\n"; 5. function3(); 6. cout << "Reach here? fun2\n"; 7. } ⑧ stack unwinding occur 1. void function1() throw ( runtime_error ) 2. { 3. Test t(1); 4. cout << "fun2 is called inside fun1\n" ; 5. function2(); 6. cout << "Reach here? Fun1\n"; 7. } Destructor 3 Destructor 2 Destructor 1 Exception occurred: runtime_error in fun3 Exception handled in main ⑤ ⑥

2019年1月1日8时24分 这里是否要强调try块?

异常处理核心技术—栈展开 每抛出一个异常,首先找到能捕获处理该异常的catch块; 利用throw语句中的”实参”对相应的”catch”块的“形参”进行初始化; 检查从抛出异常的try块首到throw之间已进行构造但尚未析构的那些处于堆栈中的局部对象,自动进行退栈和析构处理。

16.8 Stack Unwinding logic_error 1. void function3() throw ( runtime_error ) 2. { 3. cout << "In fun3\n"; 4. Test t(3); 5. throw runtime_error( "runtime_error in fun3" ); 6. cout << "Reach here? fun3\n"; 7.} 1. int main() 2. { 3. try { 4. cout << "fun1 is called inside main\n"; 5. function1(); 6. cout << "Reach here? fun main\n"; 7. } 8. catch ( runtime_error &error ) { 9. cout << "Exception occurred: " 10. << error.what() << endl; 11. cout << "Exception handled in main\n"; 12. } 13. return 0; 14. } logic_error 1. void function2() throw ( runtime_error ) 2. { 3. Test t(2); 4. cout << "fun3 is called inside fun2\n"; 5. function3(); 6. cout << "Reach here? fun2\n"; 7. } 1. void function1() throw ( runtime_error ) 2. { 3. Test t(1); 4. cout << "fun2 is called inside fun1\n" ; 5. function2(); 6. cout << "Reach here? Fun1\n"; 7. }

特别说明:由堆栈展开而调用的析构函数抛出了异常,那么terminate将被调用 调用terminate函数的情况: 对于抛出的异常,异常机制找不到匹配的catch块 析构函数试图在堆栈展开时抛出异常 在没有异常要处理时试图重新抛出异常 调用函数unexpected将默认调用函数terminate 在调用terminate函数时,函数set_terminate可以指定被调用的函数。否则默认调用abort函数(不会对自动或静态存储类对象调用析构函数)

Topics 16.1 Introduction 16.2 Exception-Handling Overview 16.3 Example: Handling an Attempt to Divide by Zero 16.4 When to Use Exception Handling 16.5 Rethrowing an Exception 16.6 Exception Specifications 16.7 Processing Unexpected Exceptions 16.8 Stack Unwinding 16.9 Constructors, Destructors and Exception Handling 16.10 Exceptions and Inheritance 16.11 Processing new Failures

16.9 Constructors, Destructors and Exception Handling 2019年1月1日8时24分 16.9 Constructors, Destructors and Exception Handling 异常处理抛出前为try语句块中构造的所有局部对象自动调用析构函数 如果一个对象包含成员对象,且在外部对象完全构造前抛出了异常,那么异常出现之前构造的成员对象将被析构 如果在异常发生时数组对象只部分构造,则只有已构造的部分被析构 第一句啥意思?

Topics 16.1 Introduction 16.2 Exception-Handling Overview 16.3 Example: Handling an Attempt to Divide by Zero 16.4 When to Use Exception Handling 16.5 Rethrowing an Exception 16.6 Exception Specifications 16.7 Processing Unexpected Exceptions 16.8 Stack Unwinding 16.9 Constructors, Destructors and Exception Handling 16.10 Exceptions and Inheritance 16.11 Processing new Failures

16.10 Exceptions and Inheritance 2019年1月1日8时24分 16.10 Exceptions and Inheritance 如果catch捕获基类类型异常对象的指针或引用,则可以捕获该基类所派生的异常对象的指针或引用。这样允许多态处理错误。 try { …… throw Cdrived; } catch (Cbase & base) {base.DoSomething();} 如何多态?如果catch捕获基类类型异常对象的指针或引用,则可以捕获该基类所派生的异常对象的指针或引用。这样允许多态处理错误。

Topics 16.1 Introduction 16.2 Exception-Handling Overview 16.3 Example: Handling an Attempt to Divide by Zero 16.4 When to Use Exception Handling 16.5 Rethrowing an Exception 16.6 Exception Specifications 16.7 Processing Unexpected Exceptions 16.8 Stack Unwinding 16.9 Constructors, Destructors and Exception Handling 16.10 Exceptions and Inheritance 16.11 Processing new Failures

16.11 Processing new Failures 2019年1月1日8时24分 16.11 Processing new Failures new failures Some compilers throw a bad_alloc exception if <new> is included Compliant to the C++ standard specification Some compilers return 0(old version) C++ standard-compliant compilers also have a version of new that returns 0 Use expression new( nothrow ), where nothrow is of type nothrow_t double *ptr = new(nothrow) double[500000]; 三种情况间的区别?

Outline (1 of 2) Fig16_05.cpp Allocate 50000000 double values new will have returned 0 if the memory allocation operation failed

Outline (1 of 2) Fig16_06.cpp Allocate 50000000 double values 2019年1月1日8时24分 Outline Fig16_06.cpp (1 of 2) Allocate 50000000 double values 这里不需要手动throw?

Outline new throws a bad_alloc exception if the memory allocation operation failed Fig16_06.cpp (2 of 2)

16.11 Processing new Failures --使用set_new_handler Function set_new_handler 函数参数为没有参数没有返回值的函数指针 一旦注册了new处理器,则不会抛出bad_alloc C++标准指出new处理器需要完成以下任务的一个 通过释放其他动态分配的内存,再次尝试分配 抛出bad_alloc异常 调用函数abort或exit结束程序

Outline Fig16_07.cpp (1 of 2) Create a user-defined new-handler function customNewHandler Register customNewHandler with set_new_handler

Outline Allocate 50000000 double values Fig16_07.cpp (2 of 2)

Summary 异常的概念 try…throw…catch模块的语法和处理流程 栈展开过程(与构造和析构的关系) 对其它异常的处理方法 new异常的处理 动态内存分配异常的处理