2010/12/14

[C++]再論C++ Exception的原罪


他們都不贊成用C++ Exception。
Joel說exception只是另一種goto;Raymond Chen說要安全使用Exception非常難?
怪了,近20年來的新語言,如VB、Java、C#、Python等,都是用Exception機制來處理error,它們都號稱比C++簡單許多,怎麼會選用一個那麼難的方式來做error handling?

他們都推廣使用C++ Exception。

為什麼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的習慣。

4 comments:

ozzy said...

不只是要安全地使用exception很難,要審核別人的code更難。如果你在審核別人的code,他是一行一行地做error code checking,你至少能一眼看出,他有努力地深思熟慮error handling。但若別人的code是用exception機制,你很難一眼看出他是否有深思熟慮過error handling的問題

> c++ exception 的目的就是use cases alternative flow 的 detailed design
只是 programming language 實踐的不同
in early stage , some senior c programmers use setjmp/longjmp to handle exception in runtime.

ozzy said...
This comment has been removed by the author.
ozzy said...
This comment has been removed by the author.
ozzy said...
This comment has been removed by the author.