深入分析异常机制!

来源:互联网 发布:淘宝 零食 店铺 推荐 编辑:程序博客网 时间:2024/04/24 10:58

 我们知道C++和C最大的不同就是它更好的支持面向对象程序设计,封装,多态,继承,异常,命名空间.通用型编程等等.

对于面向机制为什么说是更好的支持哪.是因为用C同样可以编写面向对象程序设计.我们都知道C函数可以通过结构体和函数指针来设计一些低级的类.但C++提供的CLASS则更好的维护了数据的隐藏.而不是想C那样任何数据都要通过函数来操作.C++是通过数据和方法的封装来实现对数据的操作.

至于命名空间更多的是突出模块化.把一些你所认为有理由放在一起的数据 类 函数 等等放在同一个命名空间中,来体现模块的概念,并且也减少了名字冲突.

下面我们来说说异常.异常的存在不一定总是一件很好的事,它的存在影响着程序在空间和时间上的优势.很多编译器也就因此可以设置成不支持异常的编译机制.但你要保证你的每个编译单位都没有用到异常,在连接时才能顺利连接.

而异常的存在一定是有原因的.从类库的设计到用户使用类库编程无不涉及到异常.异常是类库给用户自己当家做主的好方法.

只要你用TRY块去检查,CATCH字句是不会另你失望的.

我们拿最熟悉的OPERATOR NEW来说 ,如果分配内存失败就会抛出一个异常,BAD_ALLOC  如果你要为这件事负责就一定要有这样的代码 CATCHI(BAD_ALLOC &) {    DO  SOMETHING }

当然如果你有这样的代码set_new_handler(指向函数的指针) ; 那当OPERATOR NEW失败的时候会先调用这个函数.

在这里说一下  new handler 大概是这样的定义的  typedef   void (*new hander ) ()

也就是说new_handler是一个指向参数和返回值都为VOID 的函数指针.

所以当你  set_new_handler(指向函数的指针) ; 时 ,当operator new失败的话会先调用该函数.

而set_new_handler()的原型应该大概是这样 new hander   set_new_hander (new  handler)

返回的是之前的函数指针.所以当你自己写operator new时要注意这点,用完后要恢复. 当你为set_new_handler 传递一个0时,就不调用任何函数 在operator new 失败后.而直接抛出bad_alloc异常.

接着从异常的传递来说一下,不论通过什么方式来捕捉异常,异常抛出的时候总会发生拷贝.

比如当我们有一个自己写的异常类 error

当我们在TRY 中THROW 一个该类的异常  ,在CATCH时不论是catch(error)值传递 还是catch(error &) 异常抛出时都会拷贝一个副本.值传递的话会用这个副本拷贝到catch(error)也就是说发生了两次拷贝 如果是引用方式捕捉.则会直接用这个副本来初试化.我们知道含有隐式类型转换的类做参数时,只能在接受值对象或者const 引用对象的函数时发生转换.为什么不能为非const引用对象发生一个隐式转换大家应该很清楚,原因就是为转换产生的是临时对象.而在异常中非const 引用同样可以将抛出异常产生的这个临时副本捕获..虽然通过指针捕获没有发生指向对象的复制.但会引起型别的吻乱.

对于异常捕获时能够发生的类型转换只有2个  1 是 针对基类的CATCH可以处理派生类异常  所以一定要把派生类的CATCH写在基类CATCH的上方.因为它只按顺序来找   2是 所有指针都会转换为VOID *

因为值方式捕捉会产生2个副本 所以大家最好用引用方式捕捉异常.

顺便说一下.在CATCH中 如果THROW; 则是直接抛出捕捉时的那个副本.而 THROW 对象; 则又会发生拷贝给调用者捕获.

下面来说一下异常说明

就是在一个函数声明后边加上类似的代码 throw () 如果不加则是说该函数允许抛出任何异常.如果throw()没有任何参数则是说不允许抛出任何异常.如果一个带有throw()的函数调用了一个throw(typename)的函数,并且异常真的发生了,则会调用UNEXPECTED函数.缺省的行为就是终止程序.

所以要避免调用者的异常说明范围小于被调用函数的异常说明.

函数指针也一样

在MORE EFFECTIVE C++中说到摸板和异常说明不要同时使用,希望大家能看一下.

最后一个避免的办法就是保证为知类型的异常都会被捕获

如果发生了一个异常说明中没有的异常则会调用UNEXPECTED函数.我们可以通过set_unexpected()

原型是这样大概 unexpexted_handler set_unexpected(unexpected_handler)

typedef void (*unexpected_handler)(); 和NEW_HANDLER一样是个函数指针.

在函数中如果有类似代码throw;就会抛出一个类型为bad_exception的异常.你当然也可以自己决定抛出的类型,这样就明确的知道哪个类型是发生了异常说明中没有的异常.在CATCH中对它进行捕获,就会避免缺省的UNEXPECTED函数的行为 即终止程序!

  

原创粉丝点击