錯誤處理在程式設計中是很重要的,可以在調試,釋出的時候少了很多麻煩,以往在做軟體的時候總是少了錯誤處理,導緻使用者用來莫名其妙,在查找問題的時候也是沒有頭緒
最近在總結一些錯誤處理技巧,總共有這麼一些方法:
1.LOG
log在關鍵的時刻可以救命的東西,是以我一直提議組裡的人多使用log,但是log記多了也不好,會導緻混雜資訊太多
之前公司裡面有個3D的寫log太頻繁,結果導緻運作8小時就寫了4G的log導緻運作崩潰,當時給他找了好多天才發現是log的問題
先階段來說,我們的log主要是用在處理輸入輸出上面,是以我建議在以下幾個地方記錄log:
1.1 與外部庫最近互動的地方
這裡的外部庫就是非本公司所使用的開發庫,比如我們公司使用的BOOST, QT這些庫
1.2. IO輸入輸出的資料
主要是網絡,檔案,序列槽這些資訊,記錄資訊的時候除了有一份二進制的原始資料以外,最好還附帶一份可視化的資料
1.3. 邏輯處理的地方
這個就比較難以界定了,其實到現在我沒法很好地記錄這方面的資料,但是我的建議是,如果這個邏輯處理是和外部互動的,比如網絡,序列槽,一定要把這個邏輯給記錄下來
2.錯誤值傳回
錯誤值傳回是比較古老的方式,好處程式是按照流程來處理的,壞處就是在if内嵌if的時候代碼看起來會很雜亂,不過有do..while(false)這個技巧可以避免
3.異常處理
異常處理在C++裡面是比較争議的一種方式,最近在項目裡面我也開始使用異常處理,是以感慨比較多,但是給我的感覺就是這個不是用在錯誤處理的,之前看C++之父寫的那本書的時候,他也提到過這一點,他是在處理異常而不是來處理錯誤的,很多C++的書都告訴使用者異常處理是代替C語言方式的傳回值的,但是C++之父強調了兩點:
1.異常處理是用來處理異常的,這些異常需要是可恢複的
2.異常處理是用來解決構造函數無法報告錯誤的
但是怎麼界定錯誤和異常這個我到現在還是沒法好好地界定
之前書上很多都也都不建議使用異常,因為C++裡面沒有GC,但是我們可以使用RAII以及BOOST_EXIT和shared_ptr(其實也是RAII)來解決問題
因為好像在現代C++裡面,好像沒什麼理由再不使用異常了
在之前用python的時候,python大部分都是利用異常來處理錯誤,python使用異常處理,我一直覺得這種方法不錯,但是python本身的異常類型也有點多,如果要在C++裡面模仿這種方法,我們必須要定義很多異常類型,否則無法把足夠的異常資訊帶給外部,但是這樣會造成的檔案依賴
比如最近我在寫一個函數,這個需要将一個格式的檔案轉換成對應的資料存儲到SQL裡面,需要做如下動作:
在每一個動作的時候,如果發生錯誤,我們都需要報告給外部知道發生了什麼錯誤,以便于使用者去處理
1.讀取源檔案
1.1 檔案不存在
2.讀取對應的資料
1.1 檔案格式錯誤,或者缺少資料
3.根據對應的資料去讀取對應的圖檔
1.1 圖檔不存在,或者圖檔格式錯誤
4.建立對應的sql檔案
1.1 sql檔案本身已經存在,需要詢問使用者究竟是代替掉還是取消這個行為??
5.建立對應的表
1.1 建立表錯誤
6.将對應的資料存儲到sql檔案
1.1 執行一些sql語句發生錯誤,或者讀取對應的圖檔的時候發生錯誤,詢問使用者是要無視這個錯誤還是要繼續執行
如果在函數内發生錯誤将會有如下的處理方式:
1.直接傳回false,這種類型是無法繼續執行的 (1,2,5)
2.需要詢問使用者是否繼續執行(3,4)
最早的第一個版本我是使用異常的,但是後來發現,無法去詢問使用者是否繼續執行
然後我改用bool,無法讓外部知道是哪一步出錯了,如果要讓使用者知道哪一步錯誤,需要定義一堆的enum,而且也無法讓外部去詢問
最後我的解決方案是:
把每一個動作封裝成一個函數,然後在UI層分成每一步執行,這樣可以達到上面的效果,但是無法将動作封裝成一個函數
4.coroutine
這個是那天晚上想到的,是為了解決要尋外上面的例子裡面需要詢問外部的,在執行函數的時候傳入一個coroutine,這樣如果發生錯誤則暫停執行,傳回到外部,由外部來決定是否繼續執行