用户操作
[即时聊天] [发私信] [加为好友]
孟岩ID:myan
1673525次访问,排名9好友66人,关注者200
总是在思考存在的问题
myan的文章
原创 148 篇
翻译 0 篇
转载 3 篇
评论 5285 篇
最近评论
domemy:Linux 环境下的多核调试
— Intel + Totalview 强强联合!
目前,在软件开发行业,各种性能优异的调试工具层出不穷。但是,它们中的绝大部分都只支持windows环境。即使能支持linux平台,操作起来也很不方便。因此,对于长期在linux上编写程序的开发人员来说,如何调试就成了一个令人头痛的问题!Intel软件 和 Total……
bluehouse1985:Linux 环境下的多核调试
— Intel + Totalview 强强联合!
目前,在软件开发行业,各种性能优异的调试工具层出不穷。但是,它们中的绝大部分都只支持windows环境。即使能支持linux平台,操作起来也很不方便。因此,对于长期在linux上编写程序的开发人员来说,如何调试就成了一个令人头痛的问题!Intel软件 和 Total……
Microsoft_China_Vip:



www.soAsp.net 编程学习网 技术+ 实例应用 讲解不错。 推荐大家!

有很多 技术资料也很好!



bjblues:老大思考的真有前瞻性阿
thesameway:
51旧书网 同城易书
www.51jiushu.com
www.51jiushu.net
二手书、旧书同城交易平台
分类齐全、快速发布、准确搜索
文章分类
收藏
    相册
    测试
    友情链接
    老赵的博客
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 契约思想的一个反面案例收藏

    新一篇: 什么是契约——Eiffel的观点 | 旧一篇: 编程语言的层次观点——兼谈C++的剪裁方案

    刚刚发表了《什么是契约》一文,突然发现自己通篇都在写理论,没有实例来证明。所以赶快补充一个反面案例——C++ IOStream。说是反面,不是因为IOStream库设计得不精彩(恰恰相反,你很难找到比IOStream设计更为精彩的C++库了),而是想展示一下,在没有契约概念的思想体系里,组件设计将为权责不清的错误处理付出多大的代价。

    大家知道,C++ IOStream库非常经典,最先起源于Bjarne Stroustrup的Stream库,之后经过Jerry Schwartz、Martin Carroll、Andy Koenig等人的改进,成为IOStream库,并被并入Bell实验室发行的USD C++库中,广为传播。后来USD库逐渐消亡了,而IOStream由于获得广泛应用,得以幸免,并以新的形式被置于标准库中。

    对于错误处理,当IOStream库诞生的时候(大约1985-1987),C++还没有异常机制。因此,Jerry Schwartz发明了这样一套错误处理机制:

    例1:经典的IOStream错误处理:

      ifstream ifs("filename.txt", ios::in);
      if (!ifs) {  // 这里实施了向void*转型的操作
        // 文件打开失败,实施错误处理
      }

    先测试文件是否打开,再实施具体操作,这是经典IOStream库的一个惯用法(idiom)。

    我们现在设想用户没有很好地执行这个idiom:

      int val;
      ifstream ifs("filename.txt", ios::in);
      ifs >> val; 

    如果filename.txt打开失败,会发生什么情况?

    如果哪位还有当年的Borland C++ 3.1,可以试着测试一下。我估计是什么也不发生,或者说,程序处于极端危险的“undefined behavior”状态。

    这种情况对C++库开发者来说是不能接受的。因此,尽管问题的出现是由于用户的错误(他们没有正确地测试流状态),但是由于非契约思想体系下的权责不清,IOStream库的开发者开始追求足以应对用户错误的组件开发技术。由此,IOStream开始在一个方向上被拖入了复杂性的泥潭之中。

    我们看看标准库中的对付这种情况采用什么办法。标准IOStream有一个成员函数叫做exceptions(),专门用来帮助程序员切换异常模式。缺省情况下,异常触发并没有打开,所以情形跟经典IOStream库相同。如果你在操作IOStream之前如下调用:

    strm.exceptions(std::ios::eofbit | std::ios::failbit |
                    std::ios::badbit);
    则当流不处于good状态时,执行类似 strm >> val;这样的操作时,将会抛出异常。

    这样做看起来不错,是吗?

    我觉得不是。请恕我C++标准的异议,这是我第一次正式对C++标准中的设计提出异议。

    这种设计带来的缺点,首先是复杂。在Nicolai Josuttis的The C++ Standard Library中,对这个机制整整用了5页纸来解释,还意犹未尽。复杂的设计必然带来复杂的使用规则,而面对复杂的使用规则,用户是可以投票的,那就是你做你的,我不用!读这篇帖子的人,谁在实际项目中使用过exceptions()?事实上,我个人是害怕exception甚于害怕undefined behavior。

    而对于用户来说,你可以不用,却不得不为对它付出运行性能和空间的代价。诸位有兴趣,不妨追踪一个IOStream功能的实现,看看为了支持这个异常,IOStream库的设计这耗费了多大的心力,而你的CPU又为此耗费了多少clock。

    缺点之二,是异常本身的问题——即使你抓到了异常,又当如何?程序可能已经完全离开了发生异常时的执行环境,也许你连异常为什么发生都搞不清楚,谈何处理?也无非就是通知用户一声:“我完了,因为一个异常发生在XXXXXXXX处,你要报告的话给我发Email吧。” 是啊,你还能做什么呢?

    我们试着用契约观点来分析这一状况,如果说“先测试,再使用”在传统上是一个idiom,那么在contract思想里上升为一个契约。对于C++来说,应该将“流处于good状态”作为一个契约,在每一个成员函数里进行检查。甚至你还可以设置一个调试期标志,专门用来核查用户是否检查过流状态。在必要的操作进行之前,你可以先用断言检查用户是否检查过流状态,满足了契约。这样一来,在契约之下,用户将被迫以正确的方式使用组件,从而大幅度简化组件开发的复杂度。

    再来考虑异常。如果真正发生了异常,在Eiffel中提供了retry机制。Bjarne Stroustrup说过,retry可以做到,但是往往没有意义。为什么没有意义呢?因为C++中没有契约的思想,异常的产生可能根本就是程序员的bug。在这种情况下,无论retry多少次,结果都是一样的糟。可是在Eiffel里情形不同。如果各方面对于契约都做到很好的遵循,那么真正发生异常的时候,我们大可以比较有把握的说,这可能是一个很偶然的事件导致的。比如说网络环境下,另一个用户在那一瞬间突然对文件实施了一个操作,或者硬件的一次偶然异常。对于这种情况,“再试一次”成了合情合理的选择。我们很可能将异常扼杀在摇篮之中,从而不给上层模块带来任何影响。

    谁说契约思想不伟大呢?

     

    发表于 @ 2003年01月17日 12:56:00|评论(loading...)|编辑

    新一篇: 什么是契约——Eiffel的观点 | 旧一篇: 编程语言的层次观点——兼谈C++的剪裁方案

    评论

    #asign 发表于2004-07-10 19:26:00  IP: 218.108.208.*
    脱离技术,在哲学里说,契约思想也是很伟大的。

    #stone 发表于2005-02-05 15:54:00  IP: 61.49.199.*
    本质上和防御性编程有什么区别。
    #dhatqd 发表于2005-06-17 16:21:00  IP: 61.186.252.*
    契约思想非常有道理,让人有茅塞顿开的感觉
    #vargas 发表于2007-01-16 23:43:34  IP:
    在具体操作中,契约是用文档约定的吗?
    #vargas 发表于2007-01-17 00:00:20  IP:
    不知道哪个大牛说过“机器人与人的最大区别是人有私心,而机器人没有”,有私心人写出的代码常常也是有私心的,总希望被调用的模块或自己调用的模块,做更多的事情,提供更好的服务。上篇文中《什么是契约》,对契约的仲裁是由自己来做,那不就没有了公证性,特别是“林子大了,坏鸟就更多了”,会出现更多的混乱。是不是应该有第三方,扮演法庭的角色呢
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © 孟岩