1.异常出现的目的

在c++语言的设计和演化中,Bjarne Stroustrup说过异常的设计假定如下情况:

  1. 基本上是为了处理错误

  2. 与函数定义相比,异常处理是很少的

  3. 与函数调用相比,异常出现的频率较少

  4. 异常仅仅是语言层次上的概念

同时:

  1. 异常不是为了作为另外一种返回机制,而是一种容错机制

  2. 不是想把函数都转变成一个容错的试题,而是想作为一种机制,提供给子系统容错能力,即使各个函数在写法上没有关心全局的错误处理

  3. 并不是想将设计者都约束到一个正确的错误处理概念上,而是希望语言更有表达能力

所以说异常实际上最早出现我想更多是c++对c一种容错机制的补充,而不是对于返回值的改进,现在很多书上都提倡用异常机制替代返回值,宣称异常机制有很多优点,也有很多人鄙视异常机制,比如zero mq的作者就曾经说过,异常机制无法做到错误处理和引发错误的地方的耦合,我想他们都理解错了异常机制出现的目的

2.异常与返回值判断错误的区别(我自己的理解)

作为一种容错机制,异常并未想要取代返回值检查错误的改进,其中一个最显著的区别就是返回值即使你不是处理,并不会导致程序的崩溃,而异常会,即返回值的默认语义就是:

  1. 我这个函数会发生错误

  2. 即使我发生错误,你可以无视我的错误

而异常机制的语义就是:

  1. 如果我发生错误,你必须处理我这个错误,否则程序就会崩溃

异常机制强制你去处理一些事情,你必须明确的知道我这个函数中,我发生错误,并且我处理了他,

而返回值则没有这种强制性

还有一个比较明显的好处,就是异常可以让错误处理集中在一处处理,比如我们一个socket,在写一个socket的时候发现网络连接断开了,这个时候我们肯定是要重新去连接,如果用C语言的话一般是直接一层一层的用errCode return上去,而且在return的时候我们需要一直去检查状态

比如if(call_function() )

    return

这样你会发现你的代码里面有很多的if ... return,但是如果我们在底层使用throw出来,则不用关心那么多 了

所以我建议大家在编写c++代码的时候,要考虑下,如果我这个函数出现了错误,我是否允许一些程序继续往下执行??再来决定是否使用异常还是返回值,以上仅仅是我的个人建议,而不是bjarne stroustrup的建议

3.为什么c++不让用户知道函数会引发什么异常

既然异常机制的语义是如果我发生错误,你必须处理我这个错误,但是在函数的声明上,我们很难看出来这个函数是否需要捕获异常,因此,最早c++的设计团队有这样的想法,就是在函数的声明加上异常抛出的语义

void function(int args) throw e1,e2

这样用户在看到这个函数声明的时候就知道这个函数会抛出什么异常,其实我觉得这样挺方便的,现在我无法知道内部程序会抛什么异常一直是我所困扰的,如果这样,我们就可以在编译的时候知道我们的程序有多少未捕获的异常

假设c++真的实现了异常的静态检查,我们在编译的时候就可以直接检测到代码中的错误,会发生什么问题??

​假设我们有三个函数,其中存在不同的三个模块,

​分别为function0调用function1,function1调用function2,此时function2抛出异常e1,需要function0处理,function1和function0的模块为了不编译错误,function1必须捕获函数并且把他重新throw,而function0必须处理这个异常

后面,function2增加了异常抛出e2,此时我们为了通过编译,我们需要重新修改function1的代码,并且重新编译function1,这个修改也会影响到function0,于是我们也必须去修改function0,这样,将会导致多余的代码修改以及重编译,这个不是c++的设计团队所希望看到的

所以后来bjarne stroustrup认为这样的静态检查并不是c++所希望的,他更认为这种检查将由另外一种工具来检查更好

我在想这种语法作为一种提示语法也并非不可,只是作为提示用,编译器不会对此进行保证,不过回头想想,这跟注释有什么区别??

4:异常的核心就是资源管理

在异常里面还有一个比较头疼的就是资源管理,bjarne stroustrup也明确指出异常的设计核心实际上是资源的管理,原因在于如果一个程序打开了一个文件,程序在运行过程中抛出了异常,而文件关闭的代码则在程序抛出异常代码的后面,那么则文件无法正常关闭

于是这个时候,RAII就诞生了,我看到这里也感到有点诧异,RAII居然是因为异常诞生的

于是,不管我们是否进行文件关闭操作,只要该函数析构掉,我们的文件总能正常关闭

bjarne stroustrup也提出异常处理给构造函数提供了一种报告出错的直接方法,如果没有异常函数,那么我们将只能迂回地去检测这个函数是否构造完成,与此相反,scotter meyers还是hutter(忘记是谁了,反正是一位c++大神)建议,就是不要在构造函数中抛出异常,因为如果在构造函数里面抛出异常,那个申请的资源可能会泄漏,比如

x = new X()

如果在构造x的过程中抛出异常,那么你就无法删除new X申请的资源,这个也成了很多人嘲笑c++异常的例子

于是乎,很多程序转而另外定义一个init来供外部调用,这个也是我经常在网上看到的建议,于是你经常能看到如下的代码:

x = new X()

try

{

x->init();

}

catch(...)

{

}

但是bjarne stroustrup对对这种做法不赞成(http://www.cise.ufl.edu/~manuel/stroustrup/ex.pdf),

Having a separate init() function is an opportunity to
– Forget to call init()
– Call init() twice
– Forget to test that init() succeeded
– Forget that init() might throw an exception
– Use an object before calling init()

对此,scotter meyers在他的more effective c++的item 10有给出建议,总的来说,还是要遵守不要在构造函数里面对外抛出异常,而是在构造函数内处理异常,并且在构造函数内利用RAII来达到自动管理资源的目的,当然后一条不是必须的,只要你能保证你能够正常释放资源即可,利用RAII只是为了方便而已

 

5.为什么没有办法从发生异常的地方继续执行

我想这个是很多人一直想要的功能,当时这个问题c++讨论组也讨论了很久,最后从以往的设计角度上来看,这种所谓的唤醒机制都是不靠谱的,因此没有加入,有一个os最早就是朝着这个方向设计的,后来几乎把这部分唤醒功能全部都去掉了,我想估计c++委员会也是基于这样的考虑才不加入这个功能

 

上面的就差不多是c++异常机制设计的一些思路了,当然这里面参杂了我的一些看法,其实从这里面来看,很多人不喜欢c++是因为他不了解c++一些特性出现的原因,可能他不知道这个在c++里面实际上是错误的用法,只是c++没去禁止你使用而已

最近看<<C++的历史和演化>>感觉还是挺有意思的,了解c++的历史就知道我们在过去有多少错误的c++使用例子了

同时推荐下bjarne stroustrup的文章  Standard-Library Exception Safety

http://www.cise.ufl.edu/~manuel/stroustrup/ex.pdf

c++的历史-异常的更多相关文章

  1. javax.mail 发送邮件异常

    一.运行过程抛出异常 1.Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/mail/util/ ...

  2. #研发解决方案#基于Apriori算法的Nginx+Lua+ELK异常流量拦截方案

    郑昀 基于杨海波的设计文档 创建于2015/8/13 最后更新于2015/8/25 关键词:异常流量.rate limiting.Nginx.Apriori.频繁项集.先验算法.Lua.ELK 本文档 ...

  3. 5-Spark高级数据分析-第五章 基于K均值聚类的网络流量异常检测

    据我们所知,有‘已知的已知’,有些事,我们知道我们知道:我们也知道,有 ‘已知的未知’,也就是说,有些事,我们现在知道我们不知道.但是,同样存在‘不知的不知’——有些事,我们不知道我们不知道. 上一章 ...

  4. Magicodes.WeiChat——版本发布历史

    购买地址:https://item.taobao.com/item.htm?id=520205558575 您可以在新标签页打开此图,以查看原始图片. Magicodes.WeiChat为湖南心莱信息 ...

  5. php版本历史

    php最初就是为了快速构建一个web页面而迅速被大家广为接受的.它的好处是在代码中能内嵌html的代码,从而让程序员能再一个页面中同时写html代码和php代码就能生成一个web页面. 这篇文章用时间 ...

  6. spring+hibernate常见异常集合

    spring+hibernate出错小结: (1)java.lang.NoClassDefFoundError: org/hibernate/context/CurrentSessionContext ...

  7. js 函数声明方式以及javascript的历史

    1.function  xx(){} 2.匿名方式   window.onload=function(){dslfjdslfkjdslf}; 3.动态方式  var demo=new Function ...

  8. TRUNCATE引起CPU异常上涨

    13:05 2015/9/11 午睡醒来收到几封CPU使用率预警邮件.登录对应服务器,打开资源监视器,看到sqlservr.exe进程的CPU达到40%(平常服务器CPU消耗在10%以内).查看CPU ...

  9. C++历史(The History of C++)

    C++历史 早期C++ •1979: 首次实现引入类的C(C with Classes first implemented) 1.新特性:类.成员函数.继承类.独立编译.公共和私有访问控制.友元.函数 ...

随机推荐

  1. Error connecting to database [Can&#39;t connect to local MySQL server through socket &#39;/var/lib/mysql/mysql.sock&#39; (13)]

    参照 http://stackoverflow.com/questions/4448467/cant-connect-to-local-mysql-server-through-socket-var- ...

  2. 对C语言islower、isupper、isdigit函数的测试

    今天朋友问起了这三个函数,我就帮忙测试了下,测试后发现谭浩强第四版课本附录上上讲的不是很严谨. 我们先看下这三个函数介绍: 谭浩强第四版课本附录第396页上这样介绍: 函数名 函数原型 功能 返回值 ...

  3. 架构师养成记--8.Queue

    一.ConcurrentLinkedQueue 是一个适合在高并发场景下,无锁,无界的,先进先出原则.不允许为null值,add().offer()加入元素,这两个方法没区别:pull().peek( ...

  4. OpenCV2学习笔记(一)

    Mat - 图像的容器 在对图像进行处理时,首先需要将图像载入到内存中,而Mat就是图像在内存中的容器,管理着图像在内存中的数据.Mat是C++ 的一个类,由于OpenCV2中引入了内存自动管理机制, ...

  5. JS倒计时功能,给定时间返回规定格式倒计时时间

    重写了一下,增强了通用性,重写时发现月份和年份计算很复杂,因为月份天数不一样,年份又涉及平年闰年; 本人数学实在不佳无法写出算法,哪位大大日后写出来了分享给小弟一份,谢谢~. <!doctype ...

  6. Log4j快速使用精简版

    Log4j快速使用精简版 1.导入log4j-1.2.17.jar包 2.在src根目录下创建log4j.properties文件 log4j.rootLogger=INFO, CONSOLE, FI ...

  7. [已解决] MyBatis 中bind用法

    JAVA: TC_ENTR_FLOW selectFlowForUpdate(String ENTR_ID); XML: <select id="selectFlowForUpdate ...

  8. python3 字符串相关函数

    python版本 3.5 #Author by Liguangbo#_*_ coding:utf-8 _*_str="i like study python, welcome to my p ...

  9. Win7 64位 VS2013环境编译boost1_58_0

    备忘,发现好多不常用的东西不记笔记再想用要重新花时间找,所以试着开始记笔记,写入博客吧. 首先去官网下最新的版本 http://www.boost.org/ 写本文时boost最新版本为1_58_0, ...

  10. POJ 1988

    #include<iostream> #include<stdio.h> #include<algorithm> #define MAXN 30005 using ...