C++异常
程序有时会遇到运行阶段错误,导致程序无法正常地运行下去。例如,程序可能试图打开一个不可用的文件,请求过多的内存,或者遭遇不能容忍的值。通常程序员都会试图防止这种意外情况。C++异常为处理这种情况提供了一种功能强大而灵活的工具。
处理异常的方法
1、调用abort()
对于这类问题,处理方式之一是,调用abort()函数。Abort()函数的原型位于头文件cstdlib(或者stdlib.h)中,其典型实现是向标准错误流(即cerr使用的错误流)发送消息abnomal program termination(程序异常终止),然后终止程序。它还返回一个随实现而异的值,告诉操作系统(如果程序是由另一个程序调用的,则告诉父进程),处理失败。程序1是一个使用abort()的小程序。
// error1.cpp -- using the abort() function
#include <iostream>
#include <cstdlib>
double hmean(double a, double b);
int main()
{
double x, y, z;
std::cout << "Enter two numbers : ";
while (std::cin >> x >> y)
{
z = hmean(x, y);
std::cout << "Hamonic mean of "
<< x << " and " << y << " is " << z << std::endl;
std::cout << "Enter next set of numbers<q to quit>: ";
}
std::cout << "Bye!\n";
return 0;
}
double hmean(double a, double b)
{
if (a == -b)
{
std::cout << "untenable arguments to hmean()\n";
std::abort();
}
return 2.0 * a * b / (a + b);
}
// 程序清单1中程序的运行情况如下:
/*
Enter two numbers: 3 6
Harmonic mean of 3 and 6 is 4
Enter next set of numbers<q to quit>: 10 -10
untenable arguments to hmean()
abnomal program termination
*/
注意,在hmean()中调用abort()函数将直接终止程序,而不是先返回到main()。一般而言,显示的程序中断消息随编译器而异。
为了避免异常终止,程序应在调用hmean()函数之前检查x和y的值。然而,依靠程序员来执行这种检查是不安全的。
2、返回错误码
一种比异常终止更灵活的方法是,使用函数的返回值来指出问题。例如,ostream类的get(void)成员通常返回下一个输入字符的ASCII码,但到达文件末尾时,将返回特殊值EOF。对于hmean()来说,这种方法不管用。任何数值都是有效的返回值,因此不可能用于指出问题的特殊值。在这种情况下,可使用指针参数或引用参数来将值返回给调用程序,并使用函数的返回值来指出成功或者失败。通过告知调用程序是成功了还是失败了,使得程序可以采取除异常终止程序之外的其他措施。程序2是一个采用这种方式的实例,它将hmean()的返回值重新定义为bool,让返回值指出成功了还是失败了,另外还给该参数增加了第三个参数,用于提供答案。
//error2.cpp -- returning an error code
#include<iostream>
#include<cfloat> //(or folat.h) for DBL_MAX
bool hmean(double a, double b, double *ans);
int main()
{
double x, y, z;
std::cout << "Enter two numbers: ";
while (std::cin >> x >> y)
{
if (hmean(x, y, &z))
std::cout << "Harmonic mean of "
<< x << " and " << y << " is " << z << std::endl;
else
std::cout << "one value should not be the negative "
<< "of the other - try again.\n";
std::cout << "Enter next set of numbers<q to quit>: ";
}
std::cout << "Bye!\n";
return 0;
}
bool hmean(double a, double b, double *ans)
{
if (a == -b)
{
*ans = DBL_MAX;
return false;
}
else
{
*ans = 2.0 * a * b / (a + b);
return true;
}
}
// 程序清单2中程序的运行情况如下:
/*
Enter two numbers: 3 6
Harmonic mean of 3 and 6 is 4
Enter next set of numbers<q to quit>: 10 -10
one value should not be the negative of the other - try again.
Enter a new pair of numbers: 1 19
Harmonic mean of 1 and 19 is 1.9
Enter next set of numbers<q to quit>: q
Bye!
*/
程序说明
在程序2中,程序设计避免了错误输入导致的恶果,让用户能够继续输入。当然,设计确实依靠用户检查函数的返回值,这项工作是程序员不经常做的。
第三个参数可以是指针或引用。对内置类型的参数,很多程序员都倾向于使用指针,因为这样可以明显看出是哪个参数用于提供答案。
3、异常机制
下面介绍如何使用异常机制来处理错误。C++异常是对程序运行过程中发生的异常情况(例如被0除)的一种响应。异常提供了将控制权从程序的一个部分传递到另一个部分的途径。对异常的处理有3个组成部分:
● 引发异常
● 使用处理程序捕获异常
● 使用try块
程序在出现问题时将引发异常。例如可以修改程序清单1中的hmean(),使之引发异常,而不是调用abort()函数。throw语句实际上是跳转,即命令程序调到另一个程序。Throw关键字表示引发异常,紧随其后的值(例如字符串或对象)指出了异常的特征。
程序使用异常处理程序(exception handler)来捕获异常,异常处理程序位于要处理问题的程序中。catch关键字表示捕获异常。处理程序以关键字catch开头,随后是位于括号中的类型声明,它指出了异常处理程序要响应的异常类型;然后是一个用花括号栝起的代码块,指出要采取的措施。catch关键字和异常类型用作标签,指出当异常被引发时,程序应跳到这个位置执行。异常处理程序也被称为catch块。
//error3.cpp -- using an exception
#include<iostream>
double hmean(double a, double b);
int main()
{
double x, y, z;
std::cout << "Enter two numbers: ";
while (std::cin >> x >> y)
{
try
{
z = hmean(x, y);
}
catch (const char *s)
{
std::cout << s << std::endl;
std::cout << "Enter a new pair of numbers: ";
continue;
}
std::cout << "Hamonic mean of " << x << " and " << y
<< " is " << z << std::endl;
std::cout << "Enter next set of numbers<q to quit>: ";
}
std::cout << "Bye!\n";
return 0;
}
double hmean(double a, double b)
{
if (a == -b)
throw "bad hmean() argument: a = -b not allowed";
return 2.0 * a * b / (a + b);
}
// 程序清单3中程序的运行情况如下:
/*
Enter two numbers: 3 6
Harmonic mean of 3 and 6 is 4
Enter next set of numbers<q to quit>: 10 -10
bad hmean() aruments: a = -b not allowed
Enter a new pair of numbers: 1 19
Harmonic mean of 1 and 19 is 1.9
Enter next set of numbers<q to quit>: q
Bye!
*/