- Raymond Chen 代表Microsoft
- Joel Spolsky
他們都不贊成用C++ Exception。
Joel說exception只是另一種goto;Raymond Chen說要安全使用Exception非常難?
怪了,近20年來的新語言,如VB、Java、C#、Python等,都是用Exception機制來處理error,它們都號稱比C++簡單許多,怎麼會選用一個那麼難的方式來做error handling?
- COdE fr3@K
- Herb Sutter (C++ Coding Standards, Chapter 72, Prefer to use exceptions to report errors)
為什麼C++之中有這麼立場相左的兩派,但他們兩者說得都對?
用C++ Exception不是很方便嗎?我不用每一行、每一個子運算都要檢查error code。
只要在main()裡面用個巨大的try-catch包起來就好了。
事情沒有那麼簡單。
Exception接住了,雖說程式不會當掉。但不一定滿足了Abrahams Guarantees所要求的「最基本」的no leak。
以Raymond Chen舉的例子,
BOOL ComputeChecksum(LPCTSTR pszFile, DWORD* pdwResult) { HANDLE h = CreateFile(pszFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); HANDLE hfm = CreateFileMapping(h, NULL, PAGE_READ, 0, 0, NULL); void *pv = MapViewOfFile(hfm, FILE_MAP_READ, 0, 0, 0); DWORD dwHeaderSum; CheckSumMappedFile(pvBase, GetFileSize(h, NULL), &dwHeaderSum, pdwResult); UnmapViewOfFile(pv); CloseHandle(hfm); CloseHandle(h); return TRUE; }
若你是在CreateFileMapping()傳回NULL時立刻丟一個Execption,則前面的CreateFile()的handle就會忘了釋放。
如果你想要安全地使用exception,你得自己寫一個class CFile、class CFileMapping,它們都是在constructor時擷取資源,以scoped_ptr包裝起來。如果你的程式重度使用到FileMapping,這很值得,但如果是輕度使用,這多花的工夫不一定更省,還是乖乖地每一行檢查來得有效率。
折衝下來,反對派舉出最大的理由是,若C++ Exception沒有配合RAII(初始化時就配置資源)、Smart pointer管理資源,就會有嚴重resource leak問題。
再來,Raymond Chen的網頁說,不只是要安全地使用exception很難,要審核別人的code更難。如果你在審核別人的code,他是一行一行地做error code checking,你至少能一眼看出,他有努力地深思熟慮error handling。但若別人的code是用exception機制,你很難一眼看出他是否有深思熟慮過error handling的問題。在只有十人以內的小組內code review還算簡單,但是在數千人的程式設計師組(MS Excel開發就用到上千名程式設計師),就非常困難。
在Google Coding Style中說,若你是在全新開發的project用C++ exception,它帶來的效益比額外成本來得高。但你若是在既有的codebase中想要用exception,這些過去動用上千人力寫的code都要全重寫,這反而是划不來。
近20年來的語言,如VB、Java、C#、Python,就算你只是在main()中用個巨大的try-catch包起來,也不用擔心resource leak的問題,因為它們有GC。而C++沒有implicit GC,只有explicit GC (Smart pointers),你用到的third-party library,它們的C API都沒有自動記憶體管理,所以你不能把C++當成Java、C#來寫。
C++的原罪就是,它為了要相容於C,它很多地方都要妥協。所以你把C++與C API混用時,很多地方都還是得配合C的習慣。