仔細想想能導致一個C++程序崩潰的幾乎90%原因都是跟指針有關。空指針野指針,一不小心
程序就崩了。寫C++程序的人基本上都知道這個問題。在我們周圍避免這些問題的常規方法
也很多,諸如auto_ptr(及其他基于template的原始指針wrapper)、SAFE_DELETE。當然也
會有很多人在實現一個函數時會很勤勞地對每一個parameter進行合法判斷。
其實,我們都知道,auto_ptr這些東西始終是無法避免野指針和空指針帶來的災難。
SAFE_DELETE也不能阻止別人使用這個空指針。
在我看過的一些開源項目的代碼中,這些代碼給人的感覺就是別人總能詳細地掌控各種資源
(包括指針及其他變量)的使用情況。相比之下,公司隔壁組的老大則顯得保守很多。他要
求我們幾乎要對所有指針的使用進行空值判斷(野指針也判斷不了),當然,各種成員變量
也要進行即使現在看上去沒多大用的初始化。
也許,這樣做后程序是不會掛掉了。但是,就我們的觀點來看,這樣反而會隱藏一些BUG。
為什么我們不能詳盡地去管理一個指針?一個指針變為空了,總是因為在這之前發生了錯誤
。當然,野指針本身就是愚蠢代碼產生的東西,這里沒必要討論。空指針之所以為空,也是
因為在很多時候我們把空作為失敗/錯誤/無效的標志。
恰好上周我的一些代碼就真的在空指針上出現了問題。外網的服務器隨時會因為玩家的一些
臨界操作行為而崩潰掉。雖然我通過修改腳本來屏蔽這個問題(因為不能說停機維護就停機
維護),但是總感覺程序是不安全的。人不吃點教訓絕對不學乖。
后來我對這個問題徹底思考了一下。很多程序員都自認聰明。在寫C++程序時,我從來不提
供沒用的public接口,尤其是set/get。我也從來不對沒必要的成員變量進行初始化。我給
的理由是對于這些東西我都有很清晰的把握,我為什么要做stupid的事情?
但是,我幾乎從來沒有界定,指針在哪些情況下需要去判斷為空?函數的參數絕對不需要。
假如函數的參數就是個空指針,那是client程序員的責任。僅供模塊內使用的指針(包含其
他資源)在內部使用時也不需要去判斷。如果去判斷了,那說明你對你自己寫的模塊都缺乏
精確的把握,證明你的設計思維不夠清晰。
什么時候需要判斷?當指針依賴于外部環境時,例如讀配置文件、載入資源,因為外部因素
不確定不在自己控制范圍內,那么進行判斷。同樣,當使用了其他模塊返回的指針值時,也
需要判斷。這個其實和“外部環境”屬于同一種情況。因為我們對其他模塊也不清楚,更為
隱蔽的是(隨著其他模塊的改變,將來會在你的模塊里爆發崩潰錯誤),其他模塊由別人維
護,其變化更不受自己控制。之前我對這一點界定不是很清楚,這也是我犯錯的原因。
現在想想,像游戲服務器這種程序,里面塞著各種各樣的游戲功能。無論是哪一個模塊出現
個空指針訪問出錯的問題,都會直接讓服務器崩掉。關鍵是這個結果經常伴隨著玩家的損失
。所以理想狀態下,把每一個模塊都放置在單獨的進程里,確實是很有好處的。