我的女朋友漏電了–論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.pswp.cn/news/538491.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/538491.shtml
英文地址,請注明出處:http://en.pswp.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框架我們一般對數據庫的使用的認識是: 創建數據庫,設計表結構…