使用throw语句在可能发生异常的程序出抛出异常代码,在执行程序是使用try语句执行,并使用catch语句捕获异常,执行异常之后的操作。
与C语言的setjmp和longjmp相比,他不必在每一次语句运行之后都使用一次异常处理代码,并且,它不容易忽略异常。
throw在抛出异常时,不仅可以抛出内置类型的异常,也可以抛出自定义类型的异常。
#include <iostream> #include<string> using namespace std; class MyExpression{ public: MyExpression(const char* message) :message_(message) { cout << "MyExpression..." << endl; } MyExpression(const MyExpression & other)//拷贝构造函数; :message_(other.message_) { cout << "copy MyExpression..." << endl; } ~MyExpression(){ cout << "~MyExpression" << endl; } string WhatError() { return message_.c_str(); } private: string message_; }; double Divide(double a, double b){ if (b == 0){ MyExpression e("division is zero"); throw e; } else return a / b; } int main(){ try{ cout << Divide(5.0, 0.0) << endl; } catch (MyExpression& e){ cout << e.WhatError() << endl; } return 0; }
这个例子中可以看出,抛出自定义类型的执行步骤是首先构造一个自定义类型,然后拷贝,然后析构局部对象,然后捕获异常,最后析构拷贝的自定义类型。
这个过程与调用函数的流程相似,当返回一个对象的时候会调用拷贝构造函数。当在return处直接构造函数是,就不会调用拷贝构造函数了。比如return MyExpression(“string”),同样throw MyExpression(“string”)时也不会调用拷贝构造函数。
在异常被捕获之前,局部对象被销毁的过程称之为栈展开。一个catch就是一个异常处理器,一个异常处理器只能捕获一种类型的异常。异常匹配时,捕获的类型不做类型的转换,也就是说无法使用double类型的异常处理器捕获int类型的异常。catch(...表示可以捕获任意类型的异常)