C++ 异常处理的流程,具体为:
抛出(Throw)--> 检测(Try) --> 捕获(Catch)
异常必须显式地抛出,才能被检测和捕获到;如果没有显式的抛出,即使有异常也检测不到。
在 C++ 中,我们使用 throw 关键字来显式地抛出异常,它的用法为:
throw exceptionData;
exceptionData 是“异常数据”的意思,它可以包含任意的信息,完全有程序员决定。exceptionData 可以是 int、float、bool 等基本类型,也可以是指针、数组、字符串、结构体、类等聚合类型,请看下面的例子:
char str[] = "http://c.biancheng.net";
char *pstr = str;
class Base{};
Base obj;
throw 100; //int 类型
throw str; //数组类型
throw pstr; //指针类型
throw obj; //对象类型
一个动态数组的例子
C/C++ 规定,数组一旦定义后,它的长度就不能改变了;换句话说,数组容量不能动态地增大或者减小。这样的数组称为静态数组(Static array)。静态数组有时候会给编码代码不便,我们可以通过自定义的 Array 类来实现动态数组(Dynamic array)。所谓动态数组,是指数组容量能够在使用的过程中随时增大或减小。
下面这段代码虽然有点长,但它是一个典型的使用异常的场景,请大家耐心阅读。
#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;
}
运行结果:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Error: out of range( array length 10, access index 20 )
Error: empty array, no elements to pop.
Empty array! No elements to print.
Array 类实现了动态数组,它的主要思路是:在创建对象时预先分配出一定长度的内存(通过 malloc() 分配),内存不够用时就再扩展内存(通过 realloc() 重新分配)。Array 数组只能在尾部一个一个地插入(通过 push() 插入)或删除(通过 pop() 删除)元素。
我们通过重载过的[ ]
运算符来访问数组元素,如果下标过小或过大,就会抛出异常(第53行代码);在抛出异常的同时,我们还记录了当前数组的长度和要访问的下标。
在使用 pop() 删除数组元素时,如果当前数组为空,也会抛出错误。