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. 应用层级时空记忆模型(HTM)实现对实时异常流时序数据检测

    应用层级时空记忆模型(HTM)实现对实时异常流时序数据检测 Real-Time Anomaly Detection for Streaming Analytics Subutai Ahmad SAHM ...

  2. [转] 我所经历的IBM SOA与系统整合

    2006年,一汽大众新上来一位总经理,新加坡人,整个一国际背景高端管理人才,是德国人和中国人博弈后取得的胜利. 一汽大众过去是从总部到区域到终端一体化的大盘管理模式,很僵化很粘稠,不利用快速反应.于是 ...

  3. jenkins导致磁盘占满问题

    背景 今天登陆jenkins提示磁盘空间不足,且构建发生错误 排查问题 cd到jenkins 安装目录 执行df -h 发现root目录沾满 执行 du -ah --max-depth=1 发现是.j ...

  4. java 异常历史 和观点

    异常起源于PL/1和Mesa之类的系统中. 1.) 不在于编译器是否会强制程序员去处理错误,而是要由一致的,使用异常来报告错误 2.) 不在于什么时候进行检查,而是一定要有检查.

  5. javax.mail 发送邮件异常

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

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

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

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

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

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

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

  9. php版本历史

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

随机推荐

  1. hive-jdbc/odbc的解读和看法

    当前的项目中, 涉及到了hive-jdbc/odbc这块, 因此把这几天所调研的资料作一份总结.本文讲解hive-jdbc/hive-odbc的实现, 以期对jdbc/odbc规范和实现有个较深入的理 ...

  2. Java 性能优化实战记录(2)---句柄泄漏和监控

    前言: Java不存在内存泄漏, 但存在过期引用以及资源泄漏. (个人看法, 请大牛指正) 这边对文件句柄泄漏的场景进行下模拟, 并对此做下简单的分析.如下代码为模拟一个服务进程, 忽略了句柄关闭, ...

  3. dede首页调用栏目内容_{dede:field.content/}首页调用

    如何将已经做成单页的栏目内容调用到首页来. 常用的需要调到首页来的单页内容,比如公司简介.联系我们等内容,我们在首页可能都要进行展现.通过常规的方式,包括查阅dede官方论坛资料,都找不到比较合适的答 ...

  4. Android关于主线程和非主线程

    必须在主线程执行的任务: (1)UI更新 必须在非主线程中执行的任务 (1)Http请求 如执行:ImageHelper.getInstance().loadImageSync(picUrl); 外面 ...

  5. hdu2955 Robberies  01背包+概率

    link:http://acm.hdu.edu.cn/showproblem.php?pid=2955 首先,这个题目的背包容量不能是概率.1.精度不清楚.2.把概率相加有什么意义呢?所以,转换一下, ...

  6. Codeforces Round #128 (Div. 2)

    A. Two Problems 分两题的过题情况讨论,并且数值均不大,暴力枚举. B. Game on Paper 每次给格子染色后,考虑当前格子在正方形中的位置,然后判断对应的正方形是否都已染色. ...

  7. Hive 复习

    hive分为CLI(command line)(用的比较多) JDBC/ODBC-ThriftServer hiveServer(hive -service hiveserver),JDBC访问,一个 ...

  8. phpmyadmin导入导出大数据文件的办法

    在phpmyadmin的使用中,经常需要进行导入导出数据库的操作. 但是在导入导出大型数据库文件的时候经常会只是部分导出或者部分导入. 或者是导入导出不成功. 原因就是服务器和php.mysql限制了 ...

  9. UVA-12436 Rip Van Winkle's Code (线段树区间更新)

    题目大意:一个数组,四种操作: long long data[250001]; void A( int st, int nd ) { for( int i = st; i <= nd; i++ ...

  10. GlassFish Server is a compliant implementation of the Java EE 7 platform

    1.9 GlassFish Server Tools GlassFish Server is a compliant implementation of the Java EE 7 platform. ...