异常抛出后,从进入try块起,到异常被处理,这期间在栈上的构造的所有对象都会被自动析构。析构的顺序与构造的顺序相反。这一过程叫做解旋。
【也就是说栈模型先进后出并没有被打破,当异常throw抛掷,栈上的对象会被析构】
#includeusing namespace std; class MyException{}; class Test { public: Test(int a=0,int b=0) { this->a = a; this->b = b; cout<<"构造函数被执行"<
异常接口声明1.为了加强程序的可读性,可以在函数声明中列出可能抛出的所有异常类型。
例如:void func() throw(A,B,C,D)这个函数能够且只能抛出类型ABCD及其子类型的异常
2.如果在函数声明中没有包含异常接口声明,则此函数可以抛掷任何类型的异常
3.一个不抛出任何异常的的函数可以声明为
void func throw();
4.如果一个函数抛出了它的异常接口声明所不允许的异常,unexpected函数会被调用,该函数默认行为调用terminate函数终止程序
异常类型和异常变量的生命周期1) throw的异常是有类型的,可以是数字、字符串、类对象...
2) throw的异常是有类型的,catch严格按照类型进行匹配
#includeusing namespace std; //throe int void filecopy02(char *filename2,char *filename1) { FILE *fp1 = nullptr; FILE *fp2 = nullptr; fp1 = fopen(filename1,"rb"); if(fp1 == nullptr) { throw 1; } fp2 = fopen(filename2,"wb"); if(fp2 == nullptr) { throw 2; } char buf[256]; int readlen,writelen; readlen=fread(buf,1,256,fp1); while(!feof(fp1)) { writelen = fwrite(buf,1,readlen,fp2); if(readlen != writelen) { throw 3; } } fclose(fp1); fclose(fp2); } //throw string void filecopy03(char *filename2,char *filename1) { FILE *fp1 = nullptr; FILE *fp2 = nullptr; fp1 = fopen(filename1,"rb"); if(fp1 == nullptr) { throw "打开源文件失败"; } fp2 = fopen(filename2,"wb"); if(fp2 == nullptr) { throw "打开目标文件失败"; } char buf[256]; int readlen,writelen; readlen=fread(buf,1,256,fp1); while(!feof(fp1)) { writelen = fwrite(buf,1,readlen,fp2); if(readlen != writelen) { throw "文件拷贝过程失败"; } } fclose(fp1); fclose(fp2); } //throw class class BadSrcFile { public: void toString() { cout<<"aaaaaa"< toString(); cout<<"发生异常,打开源文件失败"< C++编译器通过throw来产生对象,C++编译器在执行对应的catch分支,相当于一个函数应用,把实参传递给形参。【当然会通过解螺旋把栈清空】
不妨把catch看作一个模板函数,会进行严格的类型匹配
异常的层次结构(继承在异常中的应用)
- 异常是类(自己创建的异常类)
- 异常派生
- 异常中的数据:数据成员
- 按引用传递异常
- 在异常中使用虚函数
class eSize { public: eSize(int index) { this->index = index; } virtual void printErr() { } private: int index; }; class eNegative:public eSize { public: eNegative(int x):eSize(x) { } virtual void printErr() { cout<<"index<0"<10000"<
标准程序库异常C++标准提供了一组标准异常类,这些类以基类Exception开始,标准程序库抛出的所有异常,都派生于该基类,这些类构成如下图的异常类的派生继承关系。该基类提供一个成员函数what()用于返回错误信息(返回类型为const char*)。在Exception类中,what()函数声明如下:
virtual const char * what()const throw();
上面包含了各个具体异常类的含义以及它们的头文件。runtime_error和logic_error是一些具体的异常类的基类,它们分别表示两大类异常。logic_error表示那些可以在程序中被预先检测到的异常,也就是说如果小心得编写程序,这些类异常能够避免,而runtime_error则表示那些难以被预先检测的异常。
一些编程语言规定只能抛掷某个类的派生类(例如java中允许抛掷的类必须派生自Exception类),C++虽然没有这项强制的要求,但仍然可以选择这样实践。例如:在程序中可以使得所有抛出的异常皆派生自Exception(或者直接抛出标准程序库提供的异常类型,或者从标准程序库提供的异常类派生出新的类),这样会带来很多方便.(因为多态)
logic_error和runtime_error两个类及其派生类,都有一个接收const string &型参数的改造函数。在构造异常对象时需要将具体的错误信息传递给该函数,如果调用该对象的what函数,就可以得到构造时提供的错误信息。
#include#include using namespace std; class Teacher { public: Teacher(int age) { if(age > 100) { throw out_of_range("年龄太大"); } this->age = age; } private: int age; }; class Dog { public: Dog() { p = new int[1024*1024*100]; //4MB } private: int *p; }; int main(void) { // try // { // Teacher t1(30); // } // catch(exception &e) // { // cout<



