C++编程技术之 异常处理(上) (二)

2014-11-23 22:19:43 ? 作者: ? 浏览: 11
如把try放到while循环中。

4.异常匹配

一个异常并不与其处理器完全相关,一个对象或者是指向派生类对象的引用都能与基类处理器匹配。最好是通过引用而不是通过值来匹配异常(防止再次拷贝)。如果一个指针被抛出,将使用通常的标准指针转换来匹配异常,但不会把一种异常类型自动转换为另一种异常类型:


[cpp]
#include
using namespace std;

class Except1{};

class Except2
{
public:
Except2(const Except1&){}
};

void f(){throw Except1();}


/*这里的抛出的异常不会做隐式转换*/
int main()
{
try{
f();
}catch(Except2&){
cout<<"inside catch(Except2)"< }catch(Except1&){
cout<<"inside catch(Except1)"< }
return 0;
}

#include
using namespace std;

class Except1{};

class Except2
{
public:
Except2(const Except1&){}
};

void f(){throw Except1();}


/*这里的抛出的异常不会做隐式转换*/
int main()
{
try{
f();
}catch(Except2&){
cout<<"inside catch(Except2)"< }catch(Except1&){
cout<<"inside catch(Except1)"< }
return 0;
}
下面的例子显示了基类的异常处理器怎样捕获派生类异常:


[cpp]
#include
using namespace std;

class X
{
public:
class Trouble{};
class Small:public Trouble{};
class Big:public Trouble{};
void f(){throw Big();}
};

/*
程序的结果就是捕获了第一个异常处理,因为第一个catch处理完了所有异常,所以其他catch不会继续处理
*/
int main()
{
X x;
try{
x.f();
}catch(X::Trouble&){
cout<<"catch Trouble"< }catch(X::Small&){
cout<<"catch Small"< }catch(X::Big&){
cout<<"catch Big"< }
return 0;
}

#include
using namespace std;

class X
{
public:
class Trouble{};
class Small:public Trouble{};
class Big:public Trouble{};
void f(){throw Big();}
};

/*
程序的结果就是捕获了第一个异常处理,因为第一个catch处理完了所有异常,所以其他catch不会继续处理
*/
int main()
{
X x;
try{
x.f();
}catch(X::Trouble&){
cout<<"catch Trouble"< }catch(X::Small&){
cout<<"catch Small"< }catch(X::Big&){
cout<<"catch Big"< }
return 0;
}
一般来说,先捕获派生类的异常,最后捕获的是基类异常。

捕获所有异常:catch(...)可以捕获所有的异常。

重新抛出异常:需要释放某些资源时,例如网络连接或堆上的内存需要释放时,通常希望重新抛出一个异常(捕获异常之后,释放资源,然后重新抛出异常)

catch(...){

//释放一些资源

throw;

}

不捕获异常:无法匹配异常的话,异常就会传递到更高一层,直到能够处理这个异常。

1.terminate()函数

当没有任何一个层次的异常处理器能够处理异常时,这个函数就会调用。terminate()函数会调用abort()使函数终止,此时,函数不会调用正常的终止函数,析构函数不会执行。

2.set_terminate()函数

可以设置自己的terminate()函数


[cpp]
#include
#include
#include
using namespace std;

void terminator()
{
cout<<"I'll be back!"< exit(0);
}

/*set_terminate返回被替换的指向terminate()函数的指针
第一次调用时,返回的是指向原terminate函数的指针*/
void (*old_terminate)()=set_terminate(terminator);

class Botch
{
public:
class Fruit{};
void f(){
cout<<"Botch::f()"< throw Fruit();
}
~Botch(){throw 'c';}
};

/*
程序在处理一个异常的时候会释放在栈上分配的对象,这时,析构函数被调用,这时候产生了第二个异常
正是这个第二个以下航导致了terminate的调用
*/
int main()
{
try{
Botch b;
b.f();
}catch(...){
cout<<"inside catch(...)"< }
return 0;
}

#include
#include
#include
using namespace std;

void terminator()
{
cout<<"I'll be back!"< exit(0);
}

/*set_terminate返回被替换的指向terminate()函数的指针
第一次调用时,返回的是指向原terminate函数的指针*/
void (*old_terminate)()=set_terminate(terminator);

class Botch
{
public:
class Fruit{};
void f(){
cout<<"Botch::f()"< throw Fruit();
}
~Botch(){throw 'c';}
};

/*
程序在处理一个异常的时候会释放在栈上分配的对象,这时,析构函数被调用,这时候产生了第二个异常
正是这个第二个以下航导致了terminate的调用
*/
int main()
{
try{
Botch b;
b.f();
}catch(...){
cout<<"inside catch(...)"< }
return 0;
}
一般来说,不要在析构函数中抛出异常。

5.清理

C++的异常处理可以使得程序从正常的处理流程跳转到异常处理流程,此时,构造函数建立起来的所有对象,析构函数一定会被调用。

下面的例子展示了当构造函数没有正常结束是不会调用相关联的析构函数。


[cpp]
#include

using namespace std;

class Trace
{
static int counter;
int objid;
public:
Trace(){
objid=counter++;
cout<<"construction Trace #"< if(objid==3)

-->

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: