1. 程式人生 > >Google C++ Style Guide的哲學

Google C++ Style Guide的哲學

Google C++ Style Guide並不是一個百科全書,也不是一個C++使用指南,但它描述適用於Google及其開源專案的編碼指南,並不追求全面和絕對正確,也有許多人置疑它的一些規則。但作為一個最具影響力的編碼規範,它裡面有許多內容值得我們研究學習。

以下主要摘自GSG負責人Titus Winters在CppCon 2014上的演講

制訂Google C++ Style Guide的目的

引導開發去做對的事,同時不易犯錯。

哲學總結

關注於讀者,而非作者

(Optimize for the reader, not the writer.)
從維護的程式碼規模以及團隊協作的角度考慮,Google C++ Style Guide的制訂更加偏向於讀者的體驗,而非程式碼作者的感受。原因是程式碼被用於閱讀和理解的開銷要遠大於編碼。

適度的規則

(Rules should pull their weight.)
法無具細則無法,所以不會列出所有不能做的事項。對於未提到內容,則遵循一個大原則:”低調 (Don’t be clever.)”。(另一種相對的做法就是,不要犯傻(Don’t be stupid)。)

標準很重要,但不能迷信

(Value the standard, but don’t Idolize.)
標準對於工作非常重要,但不代表它是萬能的。可以通過cppreference.com或stackoverflow去跟進標準的變化,以及相關的討論,這樣更有助於理解標準、使用標準。

保持一致性

(Be consistent.)
這是最為關鍵的一項。保持一致性有助於分解工作,並且更好的協作,包括自動化,減少對一些不必要的爭論。在GSG中有助於一致性的規則包括:
* Include guard的命名
* 引數順序 (先輸入,再輸出)
* 名稱空間
* 宣告順序 (類裡先public, 後private, 先方法,再成員變數)
* 命名規則
* 格式化 (這種事還是交給工具吧)

通過清晰、明確的方式避免歧義和出錯的可能性

(If something unusual is happening, leave explicit evidence for the reader)
核心是以明確的方式編寫程式碼。比如:
* 常量引用代表輸出引數,指標表示會被函式修改。
* override和final對成員函式的修飾。
* Interface類、Client類等的名稱使用相應的字尾(Interface,Client)。再
* 函式的過載就沒有使用不同的函式名來得明確。
* 可變引數、以及預設函式引數都可能導致使用者理解上的問題,而有誤用的可能。
* 使用異常處理(Exception),不如錯誤處理(Error handling)明確。

避免風險難控的實現,亦或是奇巧淫技,因為太難維護。

(Avoid constructs that are dangerous or suprising, Avoid tricky and hard-to-maintain constructs)
這裡包括了兩條,一是有風險,或者冷不丁會給個驚喜的實現方式:
* 複雜的static和全域性物件,會在退出時出現問題。
* 使用override和final可以避免錯誤使用。
* 使用異常常常會轉移錯誤,是非常危險的。

另一條是一些隱晦的技術會帶來維護上的壓力。比如:
* 不要使用巨集 (複雜,不清晰)
* 模板類超程式設計 (複雜)
* 非公有化的繼承 (可能會帶來意外驚嚇)
* 多重繼承 (很難維護)

不要汙染全域性名稱空間

(Avoid polluting the global namespace)
因為程式碼太大,如果沒有控制,全域性名稱空間裡的衝突可能性非常高。所以一個重要的規則就是限制使用全域性命空間。也是分而治之的思想。重點是:
* 將程式碼放到名稱空間裡。
* 不要在標頭檔案裡將using放到全域性名稱空間裡。它會隨著引用依賴而擴散。
* 在.cc檔案就沒那麼重要,但仍然建議將static變數放到匿名名稱空間裡,不要使用using namespace來引用其它名稱空間。

必要時向調優及實用性讓步

(Concede to optimization and practicalities when necessary)
有一些規則主要推薦某種更優的實踐。比如:
* 前置宣告 (優化編譯時間)
* Inline函式 (限定於較小的函式)
* 推薦使用前置遞增 (++i, 特別是迭代器)

關於爭議性的規則

Titus通過對兩個最具爭議的規則說明了如何運用上面的規則達成目前的結論的。兩個最具爭議的規則是:
* 不能有非常量引用的輸入引數 (No Non-const reference as function arguments)
* 不使用異常 (No use of exceptions)

我這裡只說明第一條所依據的規則:
* 一致性 (和眾多程式碼實現保持一致)
* 清晰、明確,便於排查 (有沒有不合預期的修改,甚至編譯期就可以預防問題)
* 有風險、可能帶來意外驚喜
引用的生命週期問題。原因是開發者對指標的生命週期比較敏感,但對引用的生命週期管理較容易忽視。

其中的要點就是在定義規則時要知道為什麼要制訂它,什麼時候應用它, 以及未來又將如何修改它。