exception和assert是完全不同的東西,
assert是用來確認條件與狀態的一致性的方法(用在確定該條件為真,如果不成立,則代表程式有bug),而exception是將錯誤傳遞出去(發生在隱藏錯誤與傳遞錯誤的內外邊界)。
舉例來說 在一些語言裡存取null pointer的方法時會因發exception,假如可以確定不可能是null pointer,則應使用assert來檢查是否有不預期的狀態出現,因為當exception發生時,常常會被外層try catch接住而將問題(bug)屏蔽。導致當系統出現不預期行為時,已經和發生點找不到直接的關聯
另外在switch case中enum變數的值通常會是特定的值,如果在switch block中有default,當問題發生時很可能enum變數的值是invalid直接落入default action而未發現問題,這時候用assert檢查enum值的區間就有意義,這種情況常發生在物件已經是invalid(或指到錯誤的位置)
這些bug常見於multithread的程式開發中,特別是debug相當困難,結果常是莫名的segmentation fault crash,而利用assert來檢查物件的狀態變數是否符合預期,物件的member variable是否落在valid的區間,早期發現問題。
exception常是用在邊界上的錯誤傳遞(邊界的定義不是絕對的,要看context而定,可能細至api被呼叫者與呼叫者的邊界)
assertion可以想成在系統邊界內的所有程式碼,都安全地假設狀態和值都是符合預期
至於assertion要assert什麼?
可以參考programming by contract(C.A.R. Hoare.)這樣的概念
Pre-conditions, Post-conditions, Invariants
對於使用者輸入的邊界檢查很顯然是利用exception而非assert,因為超出邊界並不是bug,
除非是經過一系列檢查後進入系統邊界內,這時候使用assert檢查就合理了
狀態跑掉常見的原因是multithread程式中lock出現問題,從而導致race condition,
另外如果物件被提早釋放掉,object內的function存取部分member variables出現不預期的值,
通常這類情況不會馬上出問題,但很容易在後面出現heap corruption,此時卻不知道是從哪裡造成的。
特別是如果大量使用asynchronous API,更難追蹤來源,並且asynchronous API的callback有可能是不同thread呼叫。
透過使用debugger可以追蹤當下發生中斷的stack frames,但需配合assert,縮小問題可能的發生點。
參考連結:
https://www.edn.com/electronics-blogs/embedded-basics/4440193/8-tips-for-squashing-bugs-using-ASSERT-in-C
https://www.cs.umd.edu/class/fall2002/cmsc214/Projects/P1/proj1.contract.html