抛出(Throw)--> 检测(Try) --> 捕获(Catch)
异常必须显式地抛出,才能被检测和捕获到;如果没有显式的抛出,即使有异常也检测不到。throw exceptionData;
exceptionData 是“异常数据”的意思,它可以包含任意的信息,完全有程序员决定。exceptionData 可以是 int、float、bool 等基本类型,也可以是指针、数组、字符串、结构体、类等聚合类型,请看下面的例子:char str[] = "http://task.lmcjl.com"; char *pstr = str; class Base{}; Base obj; throw 100; //int 类型 throw str; //数组类型 throw pstr; //指针类型 throw obj; //对象类型
#include <iostream> #include <cstdlib> using namespace std; //自定义的异常类型 class OutOfRange{ public: OutOfRange(): m_flag(1){ }; OutOfRange(int len, int index): m_len(len), m_index(index), m_flag(2){ } public: void what() const; //获取具体的错误信息 private: int m_flag; //不同的flag表示不同的错误 int m_len; //当前数组的长度 int m_index; //当前使用的数组下标 }; void OutOfRange::what() const { if(m_flag == 1){ cout<<"Error: empty array, no elements to pop."<<endl; }else if(m_flag == 2){ cout<<"Error: out of range( array length "<<m_len<<", access index "<<m_index<<" )"<<endl; }else{ cout<<"Unknown exception."<<endl; } } //实现动态数组 class Array{ public: Array(); ~Array(){ free(m_p); }; public: int operator[](int i) const; //获取数组元素 int push(int ele); //在末尾插入数组元素 int pop(); //在末尾删除数组元素 int length() const{ return m_len; }; //获取数组长度 private: int m_len; //数组长度 int m_capacity; //当前的内存能容纳多少个元素 int *m_p; //内存指针 private: static const int m_stepSize = 50; //每次扩容的步长 }; Array::Array(){ m_p = (int*)malloc( sizeof(int) * m_stepSize ); m_capacity = m_stepSize; m_len = 0; } int Array::operator[](int index) const { if( index<0 || index>=m_len ){ //判断是否越界 throw OutOfRange(m_len, index); //抛出异常(创建一个匿名对象) } return *(m_p + index); } int Array::push(int ele){ if(m_len >= m_capacity){ //如果容量不足就扩容 m_capacity += m_stepSize; m_p = (int*)realloc( m_p, sizeof(int) * m_capacity ); //扩容 } *(m_p + m_len) = ele; m_len++; return m_len-1; } int Array::pop(){ if(m_len == 0){ throw OutOfRange(); //抛出异常(创建一个匿名对象) } m_len--; return *(m_p + m_len); } //打印数组元素 void printArray(Array &arr){ int len = arr.length(); //判断数组是否为空 if(len == 0){ cout<<"Empty array! No elements to print."<<endl; return; } for(int i=0; i<len; i++){ if(i == len-1){ cout<<arr[i]<<endl; }else{ cout<<arr[i]<<", "; } } } int main(){ Array nums; //向数组中添加十个元素 for(int i=0; i<10; i++){ nums.push(i); } printArray(nums); //尝试访问第20个元素 try{ cout<<nums[20]<<endl; }catch(OutOfRange &e){ e.what(); } //尝试弹出20个元素 try{ for(int i=0; i<20; i++){ nums.pop(); } }catch(OutOfRange &e){ e.what(); } printArray(nums); return 0; }运行结果:
[ ]
运算符来访问数组元素,如果下标过小或过大,就会抛出异常(第53行代码);在抛出异常的同时,我们还记录了当前数组的长度和要访问的下标。double func (char param) throw (int);
这条语句声明了一个名为 func 的函数,它的返回值类型为 double,有一个 char 类型的参数,并且只能抛出 int 类型的异常。如果抛出其他类型的异常,try 将无法捕获,只能终止程序。double func (char param) throw (int, char, exception);
如果函数不会抛出任何异常,那么( )
中什么也不写:
double func (char param) throw ();
如此,func() 函数就不能抛出任何类型的异常了,即使抛出了,try 也检测不到。class Base{ public: virtual int fun1(int) throw(); virtual int fun2(int) throw(int); virtual string fun3() throw(int, string); }; class Derived:public Base{ public: int fun1(int) throw(int); //错!异常规范不如 throw() 严格 int fun2(int) throw(int); //对!有相同的异常规范 string fun3() throw(string); //对!异常规范比 throw(int,string) 更严格 }
//错!定义中有异常规范,声明中没有 void func1(); void func1() throw(int) { } //错!定义和声明中的异常规范不一致 void func2() throw(int); void func2() throw(int, bool) { } //对!定义和声明中的异常规范严格一致 void func3() throw(float, char*); void func3() throw(float, char*) { }
#include <iostream> #include <string> #include <exception> using namespace std; void func()throw(char*, exception){ throw 100; cout<<"[1]This statement will not be executed."<<endl; } int main(){ try{ func(); }catch(int){ cout<<"Exception type: int"<<endl; } return 0; }在 GCC 下,这段代码运行到第 7 行时程序会崩溃。虽然 func() 函数中发生了异常,但是由于 throw 限制了函数只能抛出 char*、exception 类型的异常,所以 try-catch 将捕获不到异常,只能交给系统处理,终止程序。
Exception type: int
,这说明异常被成功捕获了。在 Visual C++ 中使用异常规范虽然没有语法错误,但是也没有任何效果,Visual C++ 会直接忽略异常规范的限制,函数可以抛出任何类型的异常。
本文链接:http://task.lmcjl.com/news/8739.html