异常
前言
1、异常是一种程序控制机制,与函数机制独立和互补
函数是一种以栈结构展开的上下函数衔接的程序控制系统,异常是另一种控制结构,它依附于栈结构,却可以同时设置多个异常类型作为网捕条件,从而以类型匹配在栈机制中跳跃回馈。
2、异常设计目的:
栈机制是一种高度节律性控制机制,面向对象编程却要求对象之间有方向、有目的的控制传动,从一开始,异常就是冲着改变程序控制结构,以适应面向对象程序更有效地工作这个主题,而不是仅为了进行错误处理。
异常设计出来之后,却发现在错误处理方面获得了最大的好处。
异常处理的基本思想
1、传统的错误处理机制
通过函数返回值来处理错误。
2、异常的错误处理机制
1)C++的异常处理机制使得异常的引发和异常的处理不必在同一个函数中,这样底层的函数可以着重解决具体问题,而不必过多的考虑异常的处理。上层调用者可以再适当的位置设计对不同类型异常的处理。
2)异常是专门针对抽象编程中的一系列错误处理的,C++中不能借助函数机制,因为栈结构的本质是先进后出,依次访问,无法进行跳跃,但错误处理的特征却是遇到错误信息就想要转到若干级之上进行重新尝试,如图
3)异常超脱于函数机制,决定了其对函数的跨越式回跳。
4)异常跨越函数。
C++异常处理的实现
1、异常的基本语法
1)若有异常则通过throw操作创建一个异常对象并抛掷。
2)将可能抛出异常的程序段嵌在try块之中。控制通过正常的顺序执行到达try语句,然后执行try块内的保护段。
3)如果在保护段执行期间没有引起异常,那么跟在try块后的catch子句就不执行。程序从try块后跟随的最后一个catch子句后面的语句继续执行下去。
4)catch子句按其在try块后出现的顺序被检查。匹配的catch子句将捕获并处理异常(或继续抛掷异常)。
5)如果匹配的处理器未找到,则运行函数terminate将被自动调用,其缺省功能是调用abort终止程序。
6)处理不了的异常,可以在catch的最后一个分支,使用throw语法,向上扔。
#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std; int divide(int x, int y) { if (y == 0) { throw y;//抛异常 } return x / y; } void test1() { //试着去捕获异常 try { divide(2, 0); } catch (int)//异常是根据类型进行匹配 { cout << "除数是0!" << endl; } /*或者 catch (int e)//异常是根据类型进行匹配 { cout << "除数是" << e << "!" << endl; }*/ } void CallDivide(int x, int y) { divide(x, y); } void test2() { try { CallDivide(12, 0); } catch (int)//异常是根据类型进行匹配 { cout << "除数是0!" << endl; } } int main(void) { test1();//除数是0! test2();//除数是0! return 0; }
2、栈解旋(unwinding)
异常被抛出后,从进入try块起,到异常被抛掷前,这期间在栈上的构造的所有对象,都会被自动析构。析构的顺序与构造的顺序相反。这一过程称为栈的解旋(unwinding)。
#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std; class Person { public: Person() { cout << "对象构建!" << endl; } ~Person() { cout << "对象析构!" << endl; } }; int divide(int x, int y) { Person p1, p2; if (y == 0) { throw y;//抛异常 } return x / y; } void test1() { try { divide(10, 0); } catch (int e) { cout << "异常捕获!" << endl; } } int main(void) { test1(); //对象构建! //对象构建! //对象析构! //对象析构! //异常捕获! return 0; }
3、异常接口说明
1)为了加强程序的可读性,可以在函数声明中列出可能抛出的所有异常类型,例如:void func() throw (A, B, C , D); //这个函数func()能够且只能抛出类型A B C D及其子类型的异常。
2)如果在函数声明中没有包含异常接口声明,则此函数可以抛掷任何类型的异常,例如:void func();
3)一个不抛掷任何类型异常的函数可以声明为:void func() throw();
4)如果一个函数抛出了它的异常接口声明所不允许抛出的异常,unexpected函数会被调用,该函数默认行为调用terminate函数中止程序。
#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std; //这个函数只能抛出int char float三种类型异常,抛出其它的就报错 void func() throw(int,char,float) { throw "abc"; } //不能抛出任何异常 void func2() throw() { throw -1; } //可以抛出任何异常 void func3() throw() { } int main(void) { try { func(); } catch (char* str) { cout << str << endl; } catch (int e) { cout << "异常!" << endl; } catch (...)//捕获所有异常 { cout << "未知类型异常!" << endl; } return 0; }
4、异常类型和异常变量的生命周期
1)throw的异常是有类型的,可以是 数字、字符串、类对象。
2)throw的异常是有类型的,catch严格按照类型进行匹配。
3)注意异常对象的内存模型。
#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std; void func1() { throw 1;//抛出int类型异常 } void func2() { throw "exception";//抛出char类型异常 } class MyException { public: MyException(char* str) { error = new char[strlen(str) + 1]; strcpy(error, str); } MyException(const MyException& ex) { this->error = new char[strlen(ex.error) + 1]; strcpy(this->error, ex.error); } MyException& operator=(const MyException& ex) { if (this->error != NULL) { delete[] this->error; this->error = NULL; } this->error = new char[strlen(ex.error) + 1]; strcpy(this->error, ex.error); } void what() { cout << "未知异常!" << endl; } ~MyException() { if (error != NULL) { delete[] error; } } public: char* error; }; void func3() { throw MyException("自己写的异常!");//抛出char类型异常 } void test1() { try { func1(); } catch (int e) { cout << "异常捕获!" << endl; } try { func2(); } catch (char* str) { cout << "异常捕获!" << endl; } try { func3(); } catch (MyException e) { e.what(); } } int main(void) { test1(); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std; void func1() { throw 1;//抛出int类型异常 } void func2() { throw "exception";//抛出char类型异常 } class MyException { public: MyException() { cout << "构造函数" << endl; } MyException(const MyException& ex) { cout << "拷贝构造" << endl; } ~MyException() { cout << "析构函数" << endl; } public: char* error; }; void func() { throw MyException();//创建匿名对象 调用构造 } void test1() { //普通类型元素 引用 指针 //普通元素 异常对象catch处理完之后就析构 try { func(); } catch (MyException e) { cout << "异常捕获!" << endl; } } int main(void) { test1(); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std; void func1() { throw 1;//抛出int类型异常 } void func2() { throw "exception";//抛出char类型异常 } class MyException { public: MyException() { cout << "构造函数" << endl; } MyException(const MyException& ex) { cout << "拷贝构造" << endl; } ~MyException() { cout << "析构函数" << endl; } public: char* error; }; void func() { throw MyException(); } void test1() { //普通类型元素 引用 指针 //引用的话 不用调用拷贝构造,异常对象catch处理完之后就析构 try { func(); } catch (MyException& e) { cout << "异常捕获!" << endl; } } int main(void) { test1(); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std; void func1() { throw 1;//抛出int类型异常 } void func2() { throw "exception";//抛出char类型异常 } class MyException { public: MyException() { cout << "构造函数" << endl; } MyException(const MyException& ex) { cout << "拷贝构造" << endl; } ~MyException() { cout << "析构函数" << endl; } public: char* error; }; void func() { throw new MyException(); } void test1() { //普通类型元素 引用 指针 //指针 try { func(); } catch (MyException* e) { cout << "异常捕获!" << endl; delete e; } } int main(void) { test1(); return 0; }