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. 解决:“MediaPlayer error (1, -2147483648)”问题

    如果你使用VideoView播放过MP4视频,你可能碰到过类似下面的问题: MediaPlayer   error (1, -2147483648) 如果你查阅文档,会发现1其实代表MEDIA_ERR ...

  2. win7建立无线wifi热点的几个常见的问题

    命令行开启WiFi方法: 开启WiFi.bat netsh wlan set hostednetwork mode=allow netsh wlan set hostednetwork ssid=ss ...

  3. iis 管理员执行 aspnet_iis.exe

    如果我们在注册iis的时候,出现上图的问题,我们需要在桌面上新建一个快捷方式 然后在目标处添上我们的命令. 比如:C:\Windows\Microsoft.NET\Framework\v4.0.303 ...

  4. 递归神经网络(RNN)简介(转载)

    在此之前,我们已经学习了前馈网络的两种结构--多层感知器和卷积神经网络,这两种结构有一个特点,就是假设输入是一个独立的没有上下文联系的单位,比如输入是一张图片,网络识别是狗还是猫.但是对于一些有明显的 ...

  5. hdu3033 I love sneakers! 分组背包变形

    分组背包要求每一组里面只能选一个,这个题目要求每一组里面至少选一个物品. dp[i, j] 表示前 i 组里面在每组至少放进一个物品的情况下,当花费 j 的时候,所得到的的最大价值.这个状态可以由三个 ...

  6. jquery】常用的jquery获取表单对象的属性与值

    [jquery]常用的jquery获取表单对象的属性与值 1.JQuery的概念 JQuery是一个JavaScript的类库,这个类库集合了很多功能方法,利用类库你可以用一些简单的代码实现一些复杂的 ...

  7. 【HAOI2006】【BZOJ1051】【p1233】最受欢迎的牛

    BZOJ难得的水题(其实是HA太弱了) 原题: 每一头牛的愿望就是变成一头最受欢迎的牛.现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎. 这 种关系是具有传递性的,如果A认为B受欢迎,B ...

  8. QT GUI @创建新的工程

    开发环境: Qt 4.5 Qt Creator 1.3.0 新工程创建步骤: 1. 单击运行Qt Creator,进入欢迎页面.选择"File" -> "New F ...

  9. VC调用系统的调色板

    调用系统的调色板可以用到ChooseColor这个函数,这个函数传入一个参数为CHOOSECOLOR结构体的指针,其函数原型为 BOOL ChooseColor(LPCHOOSECOLOR lpCC) ...

  10. php(验证网址是否存在)错误

      $ra=get_headers('http://hi.baidu.com'); if($ra[0]==='HTTP/1.1 200 OK'){ echo 'ok'; } 这是错误的,因为有时会返回 ...