1. 概念
异常说明/规范(exception specification)指定, 如果函数抛出异常, 被抛出的异常将是包含在该说明中的一种, 或者是从列出的异常中派生的类型.
2. 定义
异常说明跟在函数形参表之后. 一个异常说明在关键字throw之后跟着一个(可能为空的)由圆括号括起来的异常类型列表. 如:
这个声明指出, foo是接受int值的函数, 返回void. 如果foo抛出一个异常, 该异常将是std::logic_error或std::runtime_error对象, 或者由std::logic_error或std::runtime_error派生的类型的异常.
3. 说明
- 编译时, 编译器不能也不会试图验证异常说明;
- 空说明列表指出函数不抛出任何异常;
- 如果一个函数声明没有指定异常说明, 则该函数可以抛出任意类型的异常;
- 异常说明是函数接口的一部分, 函数定义以及该函数的任意声明必须具有相同的异常说明;
- 异常说明不能用于函数重载;
- 在const成员函数声明中, 异常说明跟在const限定符之后;
- 如果函数抛出了没有在其异常说明中列出的异常, 就调用标准库函数unexpected. 默认情况下, unexpected函数调用terminate函数, terminate函数一般会终止程序;
- 异常说明/规范中不仅要包含函数本身引发的异常, 还应该包含该函数调用的其它函数引发的异常, 以此类推;
- 引发异常时, 编译器总是创建一个临时拷贝, 即使catch块中指定的是引用(这里指定引用的目的并不是避免创建拷贝以提高效率, 而是: 基类引用可以执行派生类对象.). 如:
4. 代码
#include <iostream>
class bad_hmean
{
private:
double v1;
double v2;
public:
bad_hmean(double a = 0, double b = 0) : v1(a), v2(b){}
void mesg();
};
inline void bad_hmean::mesg()
{
std::cout << "hmean(" << v1 << ", " << v2 <<"): "
<< "invalid arguments: a = -b/n";
}
class bad_gmean
{
public:
double v1;
double v2;
bad_gmean(double a = 0, double b = 0) : v1(a), v2(b){}
const char * mesg();
};
inline const char * bad_gmean::mesg()
{
return "gmean() arguments should be >= 0/n";
}
#include <iostream>
#include <cmath> // or math.h, unix users may need -lm flag
#include <cstring>
#include "usr_excep.h"
class demo
{
private:
char word[40];
public:
demo (const char * str)
{
std::strcpy(word, str);
std::cout << "demo " << word << " created/n";
}
~demo()
{
std::cout << "demo " << word << " destroyed/n";
}
void show() const
{
std::cout << "demo " << word << " lives!/n";
}
};
// function prototypes
double hmean(double a, double b) throw(bad_hmean);
double gmean(double a, double b) throw(bad_gmean);
double means(double a, double b) throw(bad_hmean, bad_gmean);
int main()
{
using std::cout;
using std::cin;
using std::endl;
double x, y, z;
demo d1("found in main()");
cout << "Enter two numbers: ";
while (cin >> x >> y)
{
try
{ // start of try block
z = means(x,y);
cout << "The mean mean of " << x << " and " << y
<< " is " << z << endl;
cout << "Enter next pair: ";
} // end of try block
catch (bad_hmean & bg) // start of catch block
{
bg.mesg();
cout << "Try again./n";
continue;
}
catch (bad_gmean & hg)
{
cout << hg.mesg();
cout << "Values used: " << hg.v1 << ", "
<< hg.v2 << endl;
cout << "Sorry, you don't get to play any more./n";
break;
} // end of catch block
}
d1.show();
cout << "Bye!/n";
return 0;
}
double hmean(double a, double b) throw(bad_hmean)
{
if (a == -b)
{
throw bad_hmean(a,b);
}
return 2.0 * a * b / (a + b);
}
double gmean(double a, double b) throw(bad_gmean)
{
if (a < 0 || b < 0)
{
throw bad_gmean(a, b);
}
return std::sqrt(a * b);
}
double means(double a, double b) throw(bad_hmean, bad_gmean)
{
double am, hm, gm;
demo d2("found in means()");
am = (a + b) / 2.0; // arithmetic mean
try
{
hm = hmean(a, b);
gm = gmean(a, b);
}
catch (bad_hmean & bg) // start of catch block
{
bg.mesg();
std::cout << "Caught in means()/n";
throw; // rethrows the exception
}
d2.show();
return (am + hm + gm) / 3.0;
}