Presentation is loading. Please wait.

Presentation is loading. Please wait.

Chapter 16 Exception Handling.

Similar presentations


Presentation on theme: "Chapter 16 Exception Handling."— Presentation transcript:

1 Chapter 16 Exception Handling

2 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.

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

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

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

6 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

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

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

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

10 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

11 例:处理除零异常 程序运行结果如下: 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. 抛出的是整数类型

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

13 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

14 异常类层次结构 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()接手处理。

15 <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风格的字符串,目的是为抛出的异常提供文本描述 }; }

16 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关键字用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换。

17 创建一个临时异常对象 打印异常错误信息 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; 打印异常错误信息

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

19 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子句被忽略,程序正常执行 为什么要区分的那么清楚和函数之间的区别?

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

21 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

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

23 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

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

25 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

26 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()

27 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)更严格 ???

28 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

29 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和无参数的函数。

30 另一个例子 #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 (...)表示可以接受任何类型的异常

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

32 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;

33 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

34 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之后的点继续执行。

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

36 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 { cout << "fun1 is called inside main\n"; function1(); cout << "Reach here? fun main\n"; 7. } 8. catch ( runtime_error &error ) { cout << "Exception occurred: " << error.what() << endl; 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. }

37 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 { cout << "fun1 is called inside main\n"; function1(); cout << "Reach here? fun main\n"; 7. } 8. catch ( runtime_error &error ) { cout << "Exception occurred: " << error.what() << endl; 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

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

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

40 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 { cout << "fun1 is called inside main\n"; function1(); cout << "Reach here? fun main\n"; 7. } 8. catch ( runtime_error &error ) { cout << "Exception occurred: " << error.what() << endl; 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. }

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

42 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

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

44 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

45 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捕获基类类型异常对象的指针或引用,则可以捕获该基类所派生的异常对象的指针或引用。这样允许多态处理错误。

46 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

47 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]; 三种情况间的区别?

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

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

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

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

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

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

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


Download ppt "Chapter 16 Exception Handling."

Similar presentations


Ads by Google