一、C++异常机制
1、处理原则
C++提供了异常机制exception用于处理错误。不能忘记异常:在异常没有得到处理时,程序将终止。每一种错误都可以用异常来报告try catch。
必须为每一个异常设计处理方式。要处理程序中抛出throw 的每一个异常。错误处理Error handling 从来都不简单。
2、常见异常
(1)错误引元
class Bad_area { }; // 用于从area函数报告错误的类型
// 计算矩形面积;
// 在输出错误引元的情况下抛出一个Bad_area 异常
int area(int length, int width)
{
if (length<=0 || width <=0) throw Bad_area();
return length*width;
}
int main(){
try {
int x= -1;
int y=2;
int z= 4;
//……
int area1 = area(x,y);
int area2 = framed_area(1,z);
int area3 = framed_area(y,z);
double ratio = area1/area3;
}
catch (Bad_area) {
cout << "Oops! bad arguments to area()\n";
}
}
(2)越界
尝试运行下面的程序
vector<int> v(10); // 具有10个int的vector
// 每一个初始化为0
// 引用方式为v[0] .. v[9]
for (int i = 0; i<v.size(); ++i) v[i] = i; // 设置值
for (int i = 0; i<=10; ++i) // 打印10个值(???)
cout << "v[" << i << "] == " << v[i] << endl;
如果使用了#include "std_lib_facilities.h"、vector的操作符[ ] (下标操作符) 就会报告错误的索引、抛出Range_error 错误、缺省行为会有所差异。
捕获越界异常
int mainO
{
try {
vector<int> v; // 一个int类型的vector
int x;
while (cin >> x) v.push_back(x); // 设置值
for (int i = 0; i<=v.size(); ++i) // 打印值
cout << "v["<< i <<”] == n << v[i] << endl;
} catch (out_of_range_error) {
cerr << "Oops! Range enor\n";
return 1;
} catch (…){ // 捕获其他所有异常
cerr << "Exception: something went wrong\n";
return 2;
}
}
(3)错误输入
double some_function()
{
double d = 0;
cin>> d;
if (!cin) error("couldn't read a double in 'some_function()' ");
// do something useful
}
void error(string s)
{
throw runtime_error(s);
}
void error(string s1, string s2)
{
throw runtime_error(sl +s2);
}
捕获异常
int main(){
try {
// 我们的程序
return 0; // 0表示成功
}
catch (runtime_error& e) {
cerr << "runtime error: " << e.what() << '\n ';
keep_window_openO;
return 1; // 1表示失败
}
catch ( ... ) {
cerr << "Oops: unknown exception!\n " ;
keep_window_open();
return 2; //2 表示失败
}
(4)类型窄化错误
narrow_cast 在std_lib_facililies.h 中定义
int x=2.9;
char c = 1066;
int xl = narrow_cast<int>(2.9); //throws
int x2 = narrow_cast<int>(2.0); // OK
char c1 = narrow_cast<char>(l066); //throws
char c2 = narrow_cast<char>(85); // OK
(5)逻辑错误
int main(){
vector<double> temps; // 温度
double temp = 0;
double sum = 0;
double high_temp = -1000;
double low_temp = 1000;
while (cin>>temp) temps.push_back(temp); // 读入温度
for (int i = 0; i<temps.size(); ++i) {
if(temps[i] > high_temp) high_temp = temps[i]; // 找到最高温度
if(temps[i] < low_temp) low_temp = temps[i]; // 找到最低温度
sum += temps[i]; // 计算总和
}
cout << "High temperature: " << high_temp << endl;
cout << "Low temperature: " << low_temp << endl;
cout << "Average temperature: " << sum/temps.size() << endl;
}
二、异常示例
1、引发异常
由除0的错误导致异常。
#include "stdafx.h"
#include "iostream.h"
int main(int argc, char* argv[])
{
int nDiv = 100; //定义一个整型变量,初始化为100
int nDivisor = 0; //定义一个整型变量,初始化为0
int nRet = nDiv / nDivisor; //进行除法运算
cout << nRet << endl; //输出结果
return 0;
}
2、捕获异常
异常被捕获,程序并未中断。
#include "stdafx.h"
#include "iostream.h"
int main(int argc, char* argv[])
{
try //捕捉异常
{
int nDiv = 100; //定义一个整型变量,初始化为100
int nDivisor = 0; //定义一个整型变量,初始化为0
int nRet = nDiv / nDivisor; //进行除法运算
cout << nRet << endl; //输出结果
}
catch(...) //处理异常
{
cout << "产生异常!" << endl;
}
return 0;
}
3、抛出异常
在程序中,异常语句通常出现在try语句块中,当程序运行到throw语句时,后面的代码不会被执行,而是跳到catch语句块中。
#include "stdafx.h"
#include "iostream.h"
int main(int argc, char* argv[])
{
try
{
int nDiv = 100; //定义一个整数,初始化为100
int nDivisor = 0; //定义一个整数,初始化为0
if (nDivisor <= 0) //如果除数小于等于0
{
throw "除数必须大于0!"; //抛出异常
}
int nRet = nDiv / nDivisor; //进行触发运算
cout << nRet << endl;
}
catch(...) //异常捕捉
{
cout << "运算失败!" << endl;
}
return 0;
}
4、自定义异常类
下面代码定义了两个异常,一个除0的异常类,一个负数异常类。
#include "stdafx.h"
#include "iostream.h"
#include "string.h"
class CDivZeroException //定义一个除零的异常类
{
public:
char ExceptionMsg[128]; //定义数据成员
CDivZeroException() //定义构造函数
{
strcpy(ExceptionMsg,"除零错误"); //设置异常信息
}
};
class CNegException //定义一个负数异常类
{
public:
char ExceptionMsg[128]; //定义数据成员
CNegException() //定义构造函数
{
strcpy(ExceptionMsg,"除数为负数错误"); //设置异常信息
}
};
bool Div(int nDiv ,int nDivisor, int &nRet) //定义除法函数
{
try //异常捕捉
{
if (nDivisor == 0) //判断除数是否为0
throw CDivZeroException(); //抛出异常
else if ( nDivisor < 0) //判断除数是否为负数
throw CNegException(); //抛出异常
else
nRet = nDiv / nDivisor; //进行除法运算
}
catch(CDivZeroException e) //捕捉除零的异常
{
cout << e.ExceptionMsg << endl; //输出异常信息
return false;
}
catch(CNegException e) //捕捉除数为负数的异常
{
cout << e.ExceptionMsg << endl; //输出异常信息
return false;
}
return true;
}
int main(int argc, char* argv[])
{
int nRet; //定义一个变量
bool bRet = Div(100, -2, nRet); //调用Div函数
return 0;
}