C++异常以及异常与析构函数

1. 抛出异常

1.1 抛出异常(也称为抛弃异常)即检测是否产生异常,在C++中,其采用throw语句来实现,如果检测到产生异常,则抛出异常。

该语句的格式为: throw 表达式;

如果在try语句块的程序段中(包括在其中调用的函数)发现了异常,且抛弃了该异常,则这个异常就可以被try语句块后的某个catch语句所捕获并处理,捕获和处理的条件是被抛弃的异常的类型与catch语句的异常类型相匹配。由于C++使用数据类型来区分不同的异常,因此在判断异常时,throw语句中的表达式的值就没有实际意义,而表达式的类型就特别重要。

1.2 抛出异常实际是作为另一种返回值来使用的。 抛出异常的好处一是可以不干扰正常的返回值,另一个是调用者必须处理异常,而不像以前c语言返回一个整数型的错误码,调用者往往将它忽略了。

1.3 举例说明

假如说A方法掉调用-->B方法调用-->C方法。 然后在B和C方法里定义了throws Exception。A方法里定义了Try Catch。

那么调用A方法时,在执行到C方法里出现了异常,那么这个异常就会从C抛到B,再从B抛到A。在A里的try catch就会捕获这个异常,然后你就可以在catch写自己的处理代码。

那么为什么当时出现了异常不去处理呢? 因为你业务逻辑调用的是A方法,你执行了A方法,当然要在A里得到异常,然后来处理。如果在C里面就处理异常,这就破坏程序结构了。 另外,A调用了C方法,假如还接着也调用了D,E,F方法,假如他们都有可能抛出异常,你说是在A里面获得处理一次好,还是在C,D,E,F得到了异常,每个都当时处理一下的好? 当时就处理异常理论上也是可以的,而且大多数时候,到底在哪处理异常,是要根据需求和项目的具体情况的。

2. 构造函数可以抛出异常。

3. C++标准指明析构函数不能、也不应该抛出异常。

C++异常处理模型是为C++语言量身设计的,更进一步的说,它实际上也是为C++语言中面向对象而服务的。C++异常处理模型最大的特点和优势就是对C++中的面向对象提供了最强大的无缝支持。那么如果对象在运行期间出现了异常,C++异常处理模型有责任清除那些由于出现异常所导致的已经失效了的对象(也即对象超出了它原来的作用域),并释放对象原来所分配的资源, 这就是调用这些对象的析构函数来完成释放资源的任务,所以从这个意义上说,析构函数已经变成了异常处理的一部分

上面的论述C++异常处理模型它其实是有一个前提假设——析构函数中是不应该再有异常抛出的。试想,如果对象出了异常,现在异常处理模块为了维护系统对象数据的一致性,避免资源泄漏,有责任释放这个对象的资源,调用对象的析构函数,可现在假如析构过程又再出现异常,那么请问由谁来保证这个对象的资源释放呢?而且这新出现的异常又由谁来处理呢?不要忘记前面的一个异常目前都还没有处理结束,因此这就陷入了一个矛盾之中,或者说无限的递归嵌套之中。所以C++标准就做出了这种假设,当然这种假设也是完全合理的,在对象的构造过程中,或许由于系统资源有限而致使对象需要的资源无法得到满足,从而导致异常的出现,但析构函数完全是可以做得到避免异常的发生,毕竟你是在释放资源呀!

假如无法保证在析构函数中不发生异常,怎么办? 虽然C++标准中假定了析构函数中不应该,也不永许抛出异常的。但实际的软件系统开发中是很难保证到这一点的。所有的析构函数的执行过程完全不发生一点异常,这根本就是天方夜谭,或者说自己欺骗自己算了。而且有时候析构一个对象(释放资源)比构造一个对象还更容易发生异常,例如一个表示引用记数的句柄不小心出错, 结果导致资源重复释放而发生异常,当然这种错误大多时候是由于程序员所设计的算法在逻辑上有些小问题所导致的,但不要忘记现在的系统非常复杂,不可能保证 所有的程序员写出的程序完全没有bug。因此杜绝在析构函数中决不发生任何异常的这种保证确实是有点理想化了。

3.1 more effective c++提出两点理由(析构函数不能抛出异常的理由):

1)如果析构函数抛出异常,则异常点之后的程序不会执行,如果析构函数在异常点之后执行了某些必要的动作比如释放某些资源,则这些动作不会执行,会造成诸如资源泄漏的问题。

2)通常异常发生时,c++的机制会调用已经构造对象的析构函数来释放资源,此时若析构函数本身也抛出异常,则前一个异常尚未处理,又有新的异常,会造成程序崩溃的问题。

3.2 那么当无法保证在析构函数中不发生异常时, 该怎么办?

其实还是有很好办法来解决的。那就是把异常完全封装在析构函数内部,决不让异常抛出函数之外。这是一种非常简单,也非常有效的方法。

~ClassName()

{

try{

do_something();

}

catch(){  //这里可以什么都不做,只是保证catch块的程序抛出的异常不会被扔出析构函数之外

}

}

3.3 析构函数中抛出异常时概括性总结

1)C++中析构函数的执行不应该抛出异常;

2)假如析构函数中抛出了异常,那么你的系统将变得非常危险,也许很长时间什么错误也不会发生;但也许你的系统有时就会莫名奇妙地崩溃而退出了,而且什么迹象也没有,崩得你满地找牙也很难发现问题究竟出现在什么地方;

3)当在某一个析构函数中会有一些可能(哪怕是一点点可能)发生异常时,那么就必须要把这种可能发生的异常完全封装在析构函数内部,决不能让它抛出函数之外(这招简直是绝杀!呵呵!);

4)一定要切记上面这几条总结,析构函数中抛出异常导致程序不明原因的崩溃是许多系统的致命内伤!

C++异常以及异常与析构函数

时间: 2024-10-11 11:19:45

C++异常以及异常与析构函数的相关文章

java异常和异常体系

16.异常 16.1程序执行过程中出现的影响程序正常运行的现象. 16.2异常语法 try{ //代码块 }catch(异常类型 e){ }catch(异常类型2 e2){ }...{ }finally{ } 注意:try:表示可能出现异常的代码块 catch:抓取异常 ,并进行处理 可以抓取多个异常,异常的范围要从小到大抓取 并且只会执行第一个匹配的异常类型 finally:最终的,不管是否出现异常,finally中的代码块始终会执行. 除虚拟机停止(system.exit(1))这种情况外

C++异常之异常说明

1. 指定异常 T   funNname( parameterlist ) throw( T1, T2,····,Tn): 其中 T 是类型, parameterlist 是参数列表, 而类型 T1, T2,····,Tn 是函数会抛出的异常. 2. 不抛出异常 T   funNname( parameterlist ) throw( ): 抛出异常类型列表为空,表示的是该函数不抛出任何类型异常. 3. 抛出任意类型的异常 T   funNname( parameterlist ): 这表示该函

21、捕捉异常和异常的使用原则

package com.exception.demo; public class Take { // 创建类 /** * 1.捕捉异常( 异常处理器大致分为 try-catch 语句快 和 finally 语句块 ) * 2.以下4种情况不会执行finall语句块 * 2.1.在finally语句块发生了异常 * 2.2.在前面的代码中使用了 System.exit() 退出程序 * 2.3.程序所在的线程死亡 * 2.4.关闭CPU * 3.异常的使用原则: * 1.在当前方法中使用 try

(4.3)uboot详解——异常和异常向量

(4.3)uboot详解--异常和异常向量 中断是一个较难掌握知识,因为它是一个过程,而不是一个结果,其中的步骤都建立在理论的层面上,需要理解.比如按下按键1会使led1亮,这个"起因-结果"的操作我想小孩子也能掌握,因为它是一个现象,但是要掌握"起因-过程-结果"却需要花一些功夫,因为这个过程需要理解.如果你认真的了解了前面两节的内容,那么现在就该到了实现"过程"的时候了. 前面两节分析了外部中断和内部中断相关的内容,这篇文章将对处理器的异常情

异常——获取异常信息

当出现异常时大家都经常会想查看异常的详细信息,什么异常,异常出现在什么位置等等. 在日常的编程中,printStackTrace是一个经常被用的方法,这个方法把异常的详细信息输出到了控制台上. 但是有一些时候我们想要把这些详细的信息以其他的方式展现,网页上.日志里.报警邮件中. Exception本身的toString,getMessage方法只是对该Exception类的本身信息,并不能帮我们找出异常点. 那么就从printStackTrace着手,将这个方法要输出的信息放到一个String里

VS 尝试从数据库进行更新时,遇到类型为“Microsoft.VSDesigner.Data.Local.ConnectionStringConverterServiceException”的异常。异常消息为:“”;

最近,由于更换机器,在新机器上运行更新数据库模型,报错: 尝试从数据库进行更新时,遇到类型为"Microsoft.VSDesigner.Data.Local.ConnectionStringConverterServiceException"的异常.异常消息为:""; 这样的错误一般都是进行Edmx 从数据库中更新到模型产生的,错误截图如图: 我用的是VS2012,数据库为MySQL 解决方案一: 找到自己的Entities.edmx文件,检查ConnectionS

异常及异常的处理机制

异常处理机制 异常和异常处理机制 异常的概念: 程序在运行时,发生了不可预测的事件,它阻止了程序按照我们程序员的预期 正常执行! 程序中的异常:   那么,我们剩下的5行代码九部会执行了 那么什么是异常的处理机制呢? 能让程序在异常发生时,按照代码预先设定的异常处理逻辑,针对性地处理异常,     让程序恢复正常并继续执行. 异常的分类和结构图 所有的异常错误和错误的父类=======>Throwtable   Throwable类是Java异常类型的顶层父类,一个对象只有是 Throwable

Python档案袋(异常与异常捕获 )

无异常捕获 程序遇到异常会中断 print( xxx ) print("---- 完 -----") 得到结果为: 有异常捕获 程序遇到异常会进入异常处理,并继续执行下面程序 try: print( xxx ) except NameError as e: print("出现错误",e) print("---- 完 -----") 抓住所有异常 try: print(xx) except Exception as e: print("-

阶段1 语言基础+高级_1-3-Java语言高级_05-异常与多线程_第1节 异常_3_异常的产生过程解析

索引改成3 数组的索引越界异常 分析异常如何产生的 原文地址:https://www.cnblogs.com/wangjunwei/p/11247642.html