我的女朋友漏电了–论C++中的失败(failure),缺陷(bug)和异常(exception)

先做个广告置入,如果喜欢这篇文章,你可以到 zhaoyan.website/blog 去查看于此类似的C/C++文章。

我承认有点标题党了,不过这真的是一篇写软件的文章,所以如果你已经抽出了一张面巾纸,那么趁早再把它完美的放回去。这篇软件文章很软,源代码不多,而且大部分都是伪代码。所以很适合所有人看。我特别推荐年轻的初学者,把纸巾放回去后,继续看下去。如果把这几个概念理清楚,对未来的工作非常有帮助。

先说失败(failure)。常见的软件的失败主要分为三种,编译失败,运行失败,结果失败。下面通过一个程序的例子来说明:


ef487dfb4d9bfc8b3a26ac7340e2fe0bb92d9fb4


你可以把编译失败理解成世界上最聪明的一堆程序员在帮你审核你的代码。如果审核失败,他们会提醒你在造成严重错误之前修改你的问题。单从这一点看,C++也比一些解释性的语言更加安全。例如源码中你想把变量l1修改一下。但是由于笔误写成了ll。C++的编译器会对你大吼的。但是Python一声也不吭,看你运行时候的笑话。

运行失败是指你已经有了可执行程序,当你运行它的时候,它crash了,挂了,死了,kick the bucket了。一个你最经常看见的输出就是访问越界内存带来的Segmentation Fault。所以请记住:男人头,女人腰,还有越界内存。这三样东西永远不要摸,否则会挂掉。

比起结果失败,你会发现运行失败是多么美好的一件事。上面的if语句是C++中非常著名的一个结果失败的例子。你的程序编译正常,运行正常,就是结果不对。而且你还不知道原因所在。另外一个常见的原因就是C++的数值计算溢出。这在C++中是非常著名的“未定义”。 C++标准委员会乐观的认为如果我“未定义”,那么天才的编译器程序员会发明一种最聪明的方法来解决这个问题。但是实际的情况是:天才的编译器程序员是最懒惰的程序员!如果你“未定义”,那么他们就什么也不干。结果就是到底发生什么,鬼知道!!!

如果你还没看懂,没关系!我再给你举了生活的例子。一个程序员根本就没有女朋友。这个就类似于编译时失败。一个程序员有个女朋友,但是他第一天就去摸人家女孩子的腰。有些地方还真是和尚摸得,你却摸不得,结果女朋友愤然离去,这可以对应运行时错误。最后一种情况当然就是结果错误了。程序员有了一个漂亮的女朋友,第一天他去摸人家的腰,女孩子不仅没有生气,还娇羞的把头靠在程序员的肩旁上,对他说:“讨厌了,你刚才把人家摸怀孕了啦!”

现在的问题就是:如何能尽早的发现女朋友是否怀孕?不对,我说错了,我是想说如何能够更早的发现失败?

首先,常见的失败的原因主要有两种,一种是缺陷(bug),另外一种是异常(exception, error)。好多人搞不清楚,所以我上段代码:


d54eea77702910acf3fe5b7be526baae46b7a67c


请注意,我说的缺陷就是bug的含义。也就是常说的虫子。缺陷主要有两种,设计缺陷和实现缺陷。上面的代码中,用名字来做为查找键值就是一种明显的设计缺陷。如果你在办公室喊一声“狗蛋”,会有好多同事答应的。另外一种实现缺陷我们上面介绍过,key==“Yan”写成了“key=Yan”。这些都会造成程序的失败。
那么我们如何能尽早的发现bug呢?一个很牛逼的工具就是unit test。不过C++也提供另外一个有力的工具,那就是assert。Assert用法是最简单的。下面我们看看它是如何发现我们的缺陷的。


36dceeb30989e2f46cec0fefd4be11429751e08a


Assert的基本理念可以应对成一句话:“反常必有妖”。上面这段代码的含义是如果发现Yan赚的钱超过了20万,那程序一定是哪里出现问题了。就像你发现你的名字出现在福布斯富豪榜上了,那富豪榜一定是印错了。你最好复查一下计算薪水的代码。如果你再阅读一下上面计算salary的代码,你就会发现是重名的设计缺陷和if的实现缺陷才让Yan的salary那么多。

关于assert,有三点需要说明,第一就是在哪里放assert和用assert验证什么? 一个基本的原则就是函数的各种输入和输出值,但是具体上则完全是根据具体的问题和程序员的经验。你可以把assert想象成传感器。要检验一辆车的质量,一个有经验的工程师知道哪里需要放传感器,用传感器检测什么。而工程师的女朋友会发现:这个颜色我不喜欢!

关于assert 的第二点就是在程序发布版中,assert是失效的。这个很好理解。一个车出厂前才需要用各种传感器来发现各种缺陷,一但发现缺陷,就应该找到缺陷的原因并修正它,直到零缺陷,你才应该把车出厂去买才对。如果用户去买车,发现车上都是传感器。这会影响用户的速度和体验;同时就算是用户发现车漏油这个问题,你让普通用户做什么呢?所以说assert只是工程师用于产品出厂前检测缺陷的,而不是用于最终产品的。当然,零缺陷只是传说,所以车厂有召回,软件公司有补丁。

Assert的第三点是现在c++支持static _assert了。它可以在编译的时候就发现问题,这印证了我前面说过的,编译失败要好于运行失败。


14cb0c0e389916bf3f1e445452aa46f68c2263cb

现在我们回来看看计算薪水的代码,看看OpenFile这一段,这里并不是缺陷,而是会发生异常。文件打不开有太多原因,权限不够,名字不对,别人给删掉了。所有这些原因都不是我们的程序能完全控制的。虽然这造成了程序的失败,但是这既不是设计缺陷,也不是实现缺陷,而是一种异常。

对于异常,我们应该用try catch捕捉到这种异常,然后根据上下文做出正确的反应。常见的异常多发生在IO,网络链接和用户交互上。它和assert一样,如果要用好很大程度上取决于具体的问题和程序员的经验。与assert不同的是,它也必须存在于产品的发布版本中。在车的例子中, 车漏油是缺陷,但是车胎扎了就是一种异常。在平时使用的时候,你也应该时刻准备着捕捉到这种异常,并做出正确的反应。这是它和缺陷最大的不一样的地方。


6fa998d24c98e8d652194499125e52a2b159b81e

没看懂吗?没关系。让我们继续程序员和女朋友的故事吧。我们上文提到的程序员自从把女朋友摸怀孕后有点怕怕了。他决定从日本买一个型号为“苍井-玛丽亚”的女朋友。拿到货后很快发现女朋友不仅漏气,而且漏电!漏气这个事,明显属于异常范围的。因为即使正常的使用,漏气也会正常地发生。所以一般厂家会提供一些胶水来应对这种情况。

但是漏电这明显是一个bug,厂家是应该用传感器在出厂前就发现并修正这一问题的。也就是说厂家是不应该把这一产品出厂来买的。你需要向厂家报告这一缺陷(bug)。正常的情况下,你会收到厂家的教科书式的回复:“It’s not a bug, It’s a feature!”。我还真的承认。女朋友漏电这个事,人家说是feature(特性),Make sense(没毛病)!

异常是一个很大的topic,感兴趣的可以查看我的两本书《C语言点滴》《Drop of knowledge of C++》 。里面有很多的关于异常的介绍。

从程序员和女朋友的故事中,我希望你能记住以下几点:
1)编译失败好于运行失败,运行失败好于结果失败。

2)失败通常由缺陷和异常造成。

3)对于缺陷(bug),用assert和单元测试在开发期间尽早发现并修正。

4)对于异常(exception),用try catch 在产品使用的全程捕捉并处理。

5)程序员就不应该找女朋友!


本文摘自异步社区,发表人:zhaoyan,作品《我的女朋友漏电了–论C++中的失败(failure),缺陷(bug)和异常(exception)未经授权,禁止转载。


推荐阅读

2018年5月新书书单(文末福利)

2018年4月新书书单

异步图书最全Python书单

一份程序员必备的算法书单

第一本Python神经网络编程图书



1e3b4e73269763cdf9de9f0bfbd3261eb7f437d5

0cb5a27fa6fbbf9cb89ce913122f899fd46b8c72


长按二维码,可以关注我们哟

每天与你分享IT好文。


异步图书”后台回复“关注”,即可免费获得2000门在线视频课程

点击阅读原文,查看更多内容


阅读原文


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/538491.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQLplus 和mysql区别_mysql和oracle的区别有哪些

MySQL和Oracle都是流行的关系数据库管理系统(RDBMS),在世界各地广泛使用;大多数数据库以类似的方式工作,但MySQL和Oracle的这里和那里总是存在一些差异的。本篇文章就给大家比较Oracle和MySQL,介绍Oracle和MySQL之间的区别&#x…

127.0.0.1与localhost的区别

2019独角兽企业重金招聘Python工程师标准>>> 区别1: localhost也叫local ,正确的解释是:本地服务器 127.0.0.1在windows等系统的正确解释是:本机地址(本机服务器) 他们的解析通过本机的host文件,windows自动将localhost解析为127.…

一个项目经理的贪嗔痴

我有时候在想,自己到底是一个什么角色?产品经理?还是一个项目经理?或者只是一个技术经理。 身边一些朋友说,自己想转行做一个产品经理,做一个伟大的产品。我奉劝他们说还是省省吧,在这样一个二三…

mysql 索引_MySQL之索引

索引查找算法BTREEBTREE查找算法演变B-TREE :普通 BTREE,平衡多路查找树(B-Tree)BTREE :叶子节点双向指针BTREE(B*TREE):枝节点的双向指针普通B-TREE增强版BTREE(B*TREE)总结:从上图看出,在BTree上有两个头…

2010年寒假学习心得

本人的博客园博客:http://www.cnblogs.com/zengmiaogen 博客园是我早期发表的博文。 ------------------------------------------ 1、心态要好,要相信自己能完成,不要担心自己完成不了,万事开头难,有挫折是正常的。…

利用5w1h写出高效的git commit

创建git commit 模板 创建模板 在个人目录下, 创建 .gitmessage vi .gitmessage 复制代码并输入以下信息 Who: Demand maker*When: versions affected*What:The content of the code changes* descrption: * wiki/task:Why:The reason*How:Influence of change* 复制…

python高维数据_t-SNE高维数据可视化(python)

t-SNE实践——sklearn教程t-SNE是一种集降维与可视化于一体的技术,它是基于SNE可视化的改进,解决了SNE在可视化后样本分布拥挤、边界不明显的特点,是目前最好的降维可视化手段。关于t-SNE的历史和原理详见从SNE到t-SNE再到LargeVis。代码见下…

java数学计算表达式_Java初学者:内建函数计算简单的数学表达式

这个应该在之前写的,忘记了,补上这次我们说一下如何用java计算数学表达式的值,比如,我们要计算sin(pi/3) cos(pi/6) 5.6^3,怎么计算呢?这里我们需要用到java的math的内建函数,所谓内建函数&am…

你是怎样的程序员?

一、程序员A 一个善于总结、能举一反三,敢于承担责任,敢于挑战自我,拥抱新技术的程序员,他的年龄意味着丰富经验,意味着效率。 他能指出并带人绕过一个一个技术大坑,笑看风云而不掉进去; 他能指…

谷歌新作gVisor:VM容器融合技术已经到来

作者|秦承刚,吴启翾,喻望,杨伟 编辑|张婵 出处丨高效开发运维 5 月 2 日,谷歌发布了一款新型的沙箱容器运行时 gVisor,号称能够为容器提供更安全的隔离,同时比 VM 更轻量。容器基于共…

安卓androidstudio访问本地接口_安卓开发之数据存储在本地的四种方式

​安卓开发之数据存储在本地的四种方式本地数据存储,在安卓开发过程中是不可避免的一个话题。这些本地的数据可能是用户的设置,程序的设置,用户的数据图片, 也可能是网络传输的一些缓冲数据。基本上我们有4种方法可以存储安卓程序的数据。第1…

java vector 线程安全_关于Vector到底是不是 线程安全的 问题

线程安全,在java的多并发编程中是重要概念,意思是,多个线程同时操作一个对象,在各种不同情况下,都不会造成不同的后果。一个经典问题,Vector到底是不是线程安全的?很多人都会回答,是…

TypeScript 2 : 获取当前日期及前后范围日期【Array】

原文链接:http://blog.csdn.net/crper/article/details/55194334 --------------------------------------------------- 前言 今天有个接口字段需求,要写一个今天及前几天的日期传过去; 在网上找了下都木有什么比较好的方案;就…

C# Winform使用Windows Media Player播放多媒体整理

一、简单使用示例步骤 1.添加Windows Media Player 组件当前是系统的 Com组件 工具箱》右键“选择项”》选择Com组件 2.控件拖拽到桌面,使用 private void button1_Click(object sender, EventArgs e) {//播放开始声音axWindowsMediaPlayer2.URL "start.mp3&q…

快学Scala习题解答—第一章 基础

原文链接:http://blog.csdn.net/ivan_pig/article/details/8249768 --------------------------------------------------------- 1 简介 近期对Scala比较感兴趣,买了本《快学scala》,感觉不错。比《Programming Scala:Tackle Multi-Core Complexity on…

java swing rectangle_Java SwingUtilities.convertRectangle方法代碼示例

本文整理匯總了Java中javax.swing.SwingUtilities.convertRectangle方法的典型用法代碼示例。如果您正苦於以下問題:Java SwingUtilities.convertRectangle方法的具體用法?Java SwingUtilities.convertRectangle怎麽用?Java SwingUtilities.c…

python 查询包_查找Python包的依赖包(语句)

Window 10家庭中文版,Python 3.6.4,今天看完了urllib3的官文(官方文档),因为没有具体使用过,所以,仍然是一知半解,但是,突然想知道 urllib3以及前面学习过的requests模块都依赖了什么其它模块。…

618选购手机正当时,好评率高达99%的手机了解一下!

一年一度的京东618年中购物狂欢节如火如荼的进行中,手机厂商们都使出了浑身解数,对消费者进行争夺。对于用户来说,618绝对是更换手机的好时机。不过,小伙伴们面对市场上的众多机型,也有可能挑花了眼,不知道…

IntelliJ IDEA 2017.2 x64 安装Scala

从官网下载好IntelliJ IDEA 和scala IntelliJ IDEA 安装scala插件 新建scala项目 建好后,发现src右键--新建---没有 .scala选项 解决方法

Django-ORM数据库操作

背景 Django框架功能齐全自带数据库操作功能,由于工作中设计巨量的api接口,需要一个很好的web后端服务框架,Django给了莫大的帮助。本文主要介绍Django的ORM框架我们一般对数据库的使用的认识是: 创建数据库,设计表结构…