# 王老师 C++ 异常处理

1.throw 表达式

Terminate函数，终止程序的执行。

2.try-catch语句

try{

包含可能抛出异常的语句；

}catch(类型名 [形参名]){

}catch(类型名 [形参名]){

}

#include <iostream>
#include <math.h>

using namespace std;

double sqrt_delta(double d){
if(d < 0)
throw 1;
return sqrt(d);
}

double delta(double a, double b, double c){
double d = b * b - 4 * a * c;
return sqrt_delta(d);
}

void main()
{
double a, b, c;
cout << "please input a, b, c" << endl;
cin >> a >> b >> c;

while(true){
try{
double d = delta(a, b, c);
cout << "x1: " << (d - b) / (2 * a);
cout << endl;
cout << "x2: " << -(b + d) / (2 * a);
cout << endl;
break;
}catch(int){
cout << "delta < 0, please reenter a, b, c.";
cin >> a >> b >> c;
}
}
}

3.重新抛出异常

#include <iostream>
using namespace std;

void fun(int x){
try{
if(x == 1)
throw 1;
if(x == 2)
throw 1.0;
if(x == 3)
throw '1';
}catch(int){
cout << "catch an int in fun()" << endl;
}catch(double){
cout << "catch an double in fun()" << endl;
}
cout << "testing exception in fun()..."<< endl;
}

void gun()
{
try{
//fun(1);
//fun(2);
//fun(3);
fun(4);
}catch(char){
cout << "catch a char in gun()" << endl;
}
cout << "testing exception in gun()..."<< endl;
}

int main()
{
gun();
}

4.扑获所有异常

catch(...){

}

error C2311: 'int' : is caught by '...' on line 7

#include <iostream>
using namespace std;

void fun()
{
try{
}catch(...){
cout << "catch all exception ..." << endl;
}catch(int){
cout << "catch int exception ..." << endl;
}
}

5.异常规范

warning C4297: 'function' : function assumed not to throw an exception but does
__declspec(nothrow) or throw() was specified on the function

#include <iostream>
using namespace std;

void function(int x) throw()
{
if(x == 1)
throw 1;
}

warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)

void function(int x) throw (int)
{
if(x == 1)
throw 1.5;
}

#include <iostream>
using namespace std;

void function(int x)throw(int)
{
if(x == 1)
throw 1;
}

int main()
{
void (*fp)(int)throw(char);
fp = function;
fp(1);
}

warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)

<补充>

#include <iostream>
using namespace std;
class A
{
};

void function(int x)throw(int)
//void function(int x)throw(A*)
{
if(x == 1)
throw new A;
}

void test() throw (A* )
{
//void (*fp)(int)throw(A);
void (*fp)(int)throw(int);
fp = function;
try{
fp(1);
}catch(int)
{
cout << "test" << endl;
throw;
}
}

int main()
{
try{
test();
}catch(A*){
cout << "test in main" <<endl;
}
return 0;
}

<补充>
1.异常处理仅仅通过类型而不是通过值来匹配的，否则又回到了传统的错误处理技术上去了，所以catch块的参数可以没有参数名称，只需要参数类型，除非要使用那个参数。
2.虽然异常对象看上去像局部对象，但并非创建在函数栈上，而是创建在专用的异常栈上，因此它才可以跨接多个函数而传递到上层，否则在栈清空的过程中就会被销毁。
3.函数原型中的异常说明要与实现中的异常说明一致，否则容易引起异常冲突。由于异常处理机制是在运行时有异常时才发挥作用的，因此如果函数的实现中抛出了没有在其异常说明列表中列出的异常，则编译器并不能检查出来。但是当运行时如果真的抛出了这样的异常，就会导致异常冲突。因为你没有提示函数的调用者：该函数会抛出一种没有被说明的即不期望的异常，于是异常处理机制就会检测到这个冲突并调用标准库函数unexcepted()，unexcepted()的默认行为就是调用terminate()来结束程序。

4.当异常抛出时局部对象如何释放？
Bjarne Stroustrup引入了“resource acquistion is initialization”思想，异常处理机制保证：所有从try到throw语句之间构造起来的局部对象的析构函数将被自动调用，然后清退堆栈（就像函数正常退出一样）。如果一直上溯到main函数后还没有找到匹配的catch块，那么系统调用terminate()终止整个程序，这种情况下不能保证所有局部对象会被正确地销毁。
5.catch块的参数应采用引用传递而不是值传递，不仅可以提高效率，还可以利用对象的多态性。另外，派生类的异常扑获要放到父类异常扑获的前面，否则，派生类的异常无法被扑获。catch(void *)要放到catch(...)前面。
6.编写异常说明时，要确保派生类成员函数的异常说明和基类成员函数的异常说明一致，即派生类改写的虚函数的异常说明至少要和对应的基类虚函数的异常说明相同，甚至更加严格，更特殊。

07-28 2586

#### C++ 异常处理 C++ 异常处理

2011年07月18日 818KB 下载

05-11 17

09-20 382

12-10 82

07-22 4257

#### C++语言 教学 课件

2009年08月13日 230KB 下载

07-06 1673

10-14 2716

08-29 2566