Exception Handling

int amount;
try {
	cin >> amount;
	if(amount < 0)
		throw amount;
}
catch(int e) {
	cout << amount << " is negative\n";
}
C++中,基本的异常处理是try-throw-catch。try block中包含想要尝试执行的语句。上例中throw amount;中的amount有时被叫做exception,throw语句叫做throw an exception,可以throw任意类型的值。当throw语句被执行时,try block中的执行被中断,程序的控制被转交给catch block,这个过程被叫做catch/handle the exception,catch block也通常被叫做exception handler。catch(int e)中的 e 被叫做catch-block parameter

如果throw语句没有被执行,在try block的最后一条语句被执行完后,会执行catch block后面的第一条语句,catch block会被忽略。如果一个exception被抛出但没有被catch,则程序会被终止,但这是合法的。如果在try block中嵌套使用try-catch并且在内层try中抛出的exception未被catch,则它会被抛出到外层try block处理并可能在那里被catch


C++中有一个预定义的函数叫做"terminate",它会在一个exception被抛出但未被catch时被调用。terminate函数会调用另一个名为"abort"的函数,abort函数会终止程序。terminate可以被redefine,进而在退出程序前调用另一个函数而不是abort,只要用"set_terminate"函数,将希望被调用的函数名作为参数传递给set_terminate即可

void end_func(void);

try {
	set_terminate(end_func);	// call end_func when an exception is not caught
	...
	throw("this is exception won't be caught")
}
catch(int) {
	...
}

throw语句可以抛出任意类型的值,通常的做法是定义一个class。try block可以throw多种类型的变量,但是在一次执行中只能抛出一个exception。一个catch block只能catch一种类型的exception,但是可以定义多个catch block来处理不同类型的exception。下例中,catch block没有parameter,如果catch block不需要parameter,只要列出类型即可。同时,"..."并不是省略,而是就可以使用三个点来表示default catch block,由于catch block的检查是顺序执行的,因此catch(...)要放在最后

class DivideByZero {};
...
try {
	if(divisor == 0)
		throw DivideByZero();
}
catch(DivideByZero) {
	cout << "Divisor is 0\n";
}
catch(...) {
	cout << "Unexplained exception\n";
}


有时可以延迟异常处理。例如,可以在一个函数定义中抛出一个exception但并不catch,然后在调用该函数的程序处再catch(此时函数要在程序的try block中被调用)。如果有exception在函数定义中被throw但没定义catch,那么这些exception类型要被列在exception specification中。如果一个函数有多次声明,则exception specification必须出现在每一次声明中,并且必须相同。一个函数的exception specification也被叫做throw list。如果有多个类型的exception,用","进行分隔。要记住exception specification是针对在函数外被处理的exception的,如果一个exception在函数中已经有对应的catch了,则它就不应该出现在exception specification中。如果一个函数定义包含了另一个可能会抛出exception但没有被catch的函数,则这个exception类型也要被包含在exception specification中

lass DivideByZero {};
void safe_divide(int dividend, int divisor) throw (DivideByZero, OtherExceptions);	// declaration
...
void safe_divide(int dividend, int divisor) throw (DivideByZero, OtherExceptions) {
	if(divisor == 0)
		throw DivideByZero();
	...
}

void function() throw (DivideByZero, AnotherException);	// only exception "DivideByZero" and "AnotherException" are treated normally, any other exception will end the program if not caught in function body
void function() throw ();	// empty exception list, all exceptions will end the program if thrown but not caught in function body
void function();	// all exceptions are treated normally
如果没有exception specification(没有throw list,连空也没有),则就相当于所有可能的exception类型都在exception specification中被列出了;而如果一个exception被抛出但却没有被列在exception specification中并且也没有在函数外被catch,则程序会终止。

由于一个derived class的object同时也是它base class的object,所以如果class D是class B的derived class并且B在exception specification中,那么被抛出的D类object也会被正常处理。当在derived class中redefine或override一个函数时,它只能有与base class中相同的exception specification,或是base class中该函数exception specification的子集。也就是说,redefine或override一个函数时,只能删除某些exception,而不能添加新的exception

class MyException {};
void f1() throw (MyException) {
	...
	throw MyException();
	...
}

void f2() {
	...
	try {
		...
		f1();
		...
	}
	catch(MyException e) {
		...
	}
	...
}
在现实中,最好的方法是将exception的throw和catch分别写到两个不同的函数中。并且,即使是这种方法最好只在不可避免的情况下抛出exception。如果能够简单地用其他方法解决问题,就不要使用exception。只在 当exception的处理方式取决于函数被调用的位置和方式 时使用exception,对于其他的情况,最好不要抛出exception

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值