c++ try–catch的语句原型如下:
try
{
//程序中抛出异常
throw value;
}
catch(valuetype v)
{
//例外处理程序段
}
在C++的异常中,程序接受到throw语句后就会自动调用析构器,把该域(try所在的大括号内)对象clean up,然后再进入catch语句(如果在循环体中就退出循环)。
这种机制会引起一些致命的错误,比如,当“类”有指针成员变量时(又是指针!),在 “类的构建器”中的throw语句引起的退出,会导致这个指针所指向的对象没有被析构。
比如:
class A{
public:
A(){
t = new char[100]; //malloc in A()
delete this; //delete object that has been defined,this program mean delete obj a
throw 0;
}
~A(){ delete[] t}
};
//因为在构造函数中抛出异常,所以无法调用析构函数,t无法释放,new出来的100字节变成内存垃圾
int func(){
A a;
A *p = new A();
delete p;
return 0;
}
所以我们可以通过把指针改为类就行了,比如模板类来代替指针,在模板类的内部设置一个析构函数。来解决问题。
如果抛出的是一个指针:
try{
throw new Y();
}catch(Y* p){
//whoops,forgot to delete..
//must delete p in this catch
}
所以,更好的一种处理方式是,抛出的异常是堆栈里面的对象,catch的时候做一个引用。
struct A{
virtual void print(){...}
};
struct B: public A{....};
try{
throw B("B error");
}catch(A& a){
a.print();
}
在C++中,如果有这样的函数:
void f(int x):throw(exception type1){
...
}
那么,在C++(在运行的时候处理异常)中,意味着在f()函数中,在运行的时候,f()函数最多只能抛出一个异常,而且是type1类型的。如果在函数f()中,抛出了别的异常,那么会有一个unexcepted异常抛出,去告诉函数f(),抛出了不是type1类型的异常。所以C++函数后面的throw是约束函数f()的:
void f():throw(){...} //函数f()不抛出任何异常,如果抛出,则unexcepted异常抛出 void f(){...} //函数f()可以抛出任何异常 void f():throw(T){...} //函数f()抛出T类型或T子类异常
而在Java中异常是在编译的时候处理的,如果是上面这样的函数,则是提示调用f()的时候,需要对type1的异常做出处理。也就是在try–catch中有针对type1的处理。(约束调用函数f()的调用者)
- void f():throw(){...} //函数f()抛出任何异常,如果抛出
- void f(){...} //函数f()不抛出任何异常
- void f():throw(T){...} //函数f()抛出T类型或T子类异常