异常处理(一)

        对于编写小的程序,可能会觉得没有异常处理,我们一样可以很好的完成任务。但对于一个大型程序,涉及多个模块之间相互通信,如果没有异常处理,那么发生了问题,将不知道从哪里开始查找问题。异常处理可以在问题发生时,定位到问题发生的地方,同时给你一些异常相关的信息。这些信息对于分析和解决问题有很大的帮助,异常处理是大型程序开发必不可少的一个环节。
      通过异常我们能够将问题的检测问题的解决分离出来,这样程序的问题检测部分不用关心问题是怎么处理的。问题检测部分抛出一个对象给处理代码(问题的解决部分),通过这个对象的类型和内容,找出与之匹配的处理代码。
        抛出异常
        异常是通过抛出(throw)对象而引发的。被抛出对象的类型决定了应该激活哪个处理代码。通过遵循这样的原则,选择调用链中与被抛出对象类型匹配且离抛出位置最近的那个作为处理代码。这里需要解释下调用链,调用链是指函数多层次调用时,会形成一个调用链。例如函数func1()调用func2(),func2()调用func3(),...,这样就会形成一个函数调用链。假如在func3()中发生异常,则它首先在func3()中查找是否有与被抛出对象类型匹配的处理代码,如果没有则在func2()中查找,一直到最顶层的调用函数。如果最终都没有找到与异常对象类型匹配的处理代码,则会调用标准库terminate函数。一般而言,terminate函数将调用absort函数,强制从整个程序非正常退出。如果在func2()中找到了与异常类型匹配的处理代码,则停止向上层调用函数查找,即最近原则。
        下面来说说异常对象。我们可以把异常以类似于将实参传递给函数的方式来抛出和捕获。异常可以是传给非引用形参的任意类型,这意味着必须可以复制该类型的对象。异常对象是通过复制被抛出表达式的结果来创建的,该结果必须是可以复制的类型。例如,throw runtime_error("data type must be the same"),将根据表达式结果创建一个runtime_error异常对象。需要注意的是,在执行throw的时候,不会执行跟在throw后面的语句,而是将控制从throw转移到匹配的catch,该catch可以是同一个函数中局部的catch,也可以在直接或间接调用发生异常函数的catch。当控制从一个地方传递到另一个地方时,抛出异常的块中的局部存储将不存在了。因为在处理异常的时候会释放局部存储,所以被抛出对象就不能是局部存储,而是用throw表达式初始化一个异常对象的特殊对象。该对象由编译器管理,并且驻留在可能被激活的任意catch都可以访问的空间。异常对象将传递给对应的catch,并且在完全处理了异常之后撤销。
         抛出异常的时候,会暂停当前函数的执行,开始查找匹配的catch子句。首先检查throw本身是否在try块内部,如果是,检查与该try块相关的catch子句,看是否其中之一与被抛出的对象是否匹配。如果找到匹配的catch,就异常处理;如果找不到,就退出当前函数(释放当前函数的内存并撤销局部对象),并且继续在调用函数中查找。
        这个过程称之为栈展开,沿嵌套函数调用链继续向上,直至为异常找到一个catch子句。只要找到能够处理异常的catch子句,就进入该catch子句,并在该处理代码中继续执行。当catch结束时,再紧接着与该try块相关的最后一个catch子句之后的点继续执行。
       如果找不到匹配的catch,即遇到未捕获的异常时,程序就调用库函数terminate。这样不会让程序在错误中一直运行。

           捕获异常
           catch子句中的异常说明符是在catch后面跟一个(可选)形参名的类型名。例如catch(exception &s)。异常说明符的类型决定了处理代码能够捕获的异常类型。异常类型必须是完全类型,即是内置类型或是程序员自定义的类型。例如,为runtime_error类型的说明符可以捕获runtime_error类型的错误,logic_error类型的说明符可以捕获logic_error类型的错误。
         在查找匹配的catch期间,找到的catch不必是与异常最匹配的那个catch,相反,将选择第一个找到的可以处理该异常的catch。因此,在catch子句列表中,最特殊的catch必须最先出现。
        进入catch的时候,用异常对象初始化catch的形参,就像函数形参一样,异常说明符可以是引用。像形参声明一样,基类的异常说明符可以用于捕获派生类型的异常。
      
        重新抛出
        有可能单个catch不能完全处理一个异常,必须由函数调用链中更上层的函数来处理,此时可以通过重新抛出将异常传递给函数调用链中更上层的函数。重新抛出是后面不跟类型或表达式的一个throw语句。即
throw;
空throw语句将重新抛出异常对象,它只能出现在catch或从catch调用的函数中。如果在非catch或catch调用的函数中碰到空throw,就调用terminate函数,会导致程序异常终止。需要注意的是被抛出的异常是原来的异常对象,而不是catch形参。
      捕获所有异常
      即使函数不能处理被抛出的异常,它也可能在随抛出异常退出之前执行一些动作。除了为每个可能的异常提供特定的catch子句之外,还可以使用捕获所有异常catch子句(catch-all)的。捕获所有异常的catch子句形式为(...),例如:
   catch (...) { 捕获所有异常的处理代码}
catch(...)经常与重新抛出表达式结合使用,catch完成可做的所有局部工作,然后重新抛出异常:

try{

}

catch (...){
        throw;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值