C++ 編程規範

組織和策略問題程序員

 

第0條 不要拘泥於小節(又名:瞭解哪些東西不該該標準化)算法

    無需在多個項目或者整個公司範圍內強制實施一致的編碼格式。編程

 

第1條 在高警告級別乾淨利落地進行編譯數組

    高度重視警告:使用編譯器的最高警告級別。經過修改代碼而不是下降警告級別來排除警告。安全

 

第2條 使用自動構建系統數據結構

    一鍵構建。多線程

 

第3條 使用版本控制系統併發

    svn。框架

 

第4條 在代碼審查上投入異步

    作好同行評審。

 

設計風格

第5條 一個實體應該只有一個緊湊的職責

    一次只解決一個問題。一個實體(變量、類、函數、名稱空間、模塊和庫)或一個模塊,只賦予一個良好的職責,不要亂髮散。

 

第6條 正確、簡單和清晰第一

    代碼是寫給人看的,要簡單、清晰、可靠。

 

第7條 編程中應知道什麼時候和如何考慮可伸縮性

    關注算法的優化,注意複雜性。

 

第8條 不要進行不成熟的不要進行不成熟的優化,優化應該使代碼更清晰易讀,易理解,易重構,而不要爲了所謂的性能,讓代碼變得更復雜和更差的可讀性。

 

第9條 不要進行不成熟的劣化

    不要使用低效的用法,好比++,應傾向於使用前++,而不是會產生臨時變量的後++。

 

第10條 儘可能減小全局和共享數據

    全局和共享數據,會增長耦合度,下降可維護性。

 

第11條 隱藏信息

    模塊或對象設計,內部實現與外部接口要分離,減小依賴性。

 

第12條 懂得什麼時候和如何進行併發性編程

    多線程,與平臺相關。當心使用各類多線程技術。  儘可能減小共享對象,安全地共享必須共享的對象。

 

第13條 確保資源爲對象所擁有。使用顯式的RAII和智能指針

    「資源獲取即初始化」,是處理資源獲取和釋放的C++慣用法。局部對象的構造函數和析構函數,居然能夠解決資源自動釋放的難題,C++真是無時無刻不讓人驚歎。

 

編程風格

第14條 寧要編譯時和鏈接時錯誤,也不要運行時錯誤

    C++屬於靜態類型語言,應當好好利用其靜態類型檢查。多依賴編譯時檢查,而不要過多的依賴運行時檢查。


第15條 積極使用const

    Const是咱們的好朋友。

 

第16條 避免使用宏

    C++中幾乎不須要宏:const/enum,inline,template,namespace等多種機制,分別取代宏大做用。固然頭文件中的#ifndef那個仍是沒有好的選擇。


第17條 避免使用「魔數」

    硬編碼的數字,應當使用常量代替。

 

第18條 儘量局部地聲明變量

    變量用的着的時候才定義,定義立刻初始化。

 

第19條 老是初始化變量


第20條 避免函數過長,避免嵌套過深


第21條 避免跨編譯單元的初始化依賴

    不一樣編譯單元中的名字空間級對象,其初始化順序是未定義的。

 

第22條 儘可能減小定義性依賴。避免循環依賴

    只須要聲明的時候,就不要提供定義。

 

第23條 頭文件應該自給自足

     應該確保每一個頭文件都可以獨立進行編譯,須要包含其內容所依賴的全部頭文件。

 

第24條 老是編寫內部#include保護符,決不要編寫外部#include保護符

    #ifndef xxx #define xxx #endif,這個破玩意。

 

函數與操做符
第25條 正確地選擇經過值、(智能)指針或者引用傳遞參數

分清輸入/輸出參數。

 

第26條 保持重載操做符的天然語義

    不要定義和操做符名稱不符的重載。

 

第27條 優先使用算術操做符和賦值操做符的標準形式

            a+b 定義爲 a+=b          

 

第28條 優先使用++和--的標準形式。優先調用前綴形式

    T& T::operator++(); //前綴形式

    T& T::operator++(int); //後綴形式

 

第29條 考慮重載以免隱含類型轉換

 

第30條 避免重載&&、||或 ,(逗號)

 

第31條 不要編寫依賴於函數參數求值順序的代碼

    不一樣的編譯器處理函數參數求值順序可能不同。

 

類的設計與繼承
第32條 弄清所要編寫的是哪一種類

    不一樣種類的類適用於不一樣用途。值類?基類?traits類?策略類?異常類?

 

第33條 用小類代替巨類

    小類更易於編寫,更易於保證正確、測試和使用。小類更有可能適用於各類不一樣狀況。

    小的類粒度層次恰到好處,被人使用和重用的可能性也越大,更易於部署。

 

第34條 用組合代替繼承

    繼承是緊密的耦合關係。「組合」就是指在一個類型中嵌入另外一個類型的成員變量。用這種方式可以保存和使用對象,還能控制耦合強度。

 

第35條 避免從並不是要設計成基類的類中繼承

    不要再不須要的狀況下使用繼承。要繼承的話,就要設計專門的基類。

 

第36條 優先提供抽象接口

    抽象接口是徹底由(純)虛函數構成的抽象類,沒有狀態(成員數據)。抽象基類必須負責定義功能,而不是實現功能。策略應該上推,而實現應該下放。

 

第37條 公用繼承便可替換性。繼承,不是爲了重用,而是爲了被重用

    公用繼承可以使基類的指針或者引用實際指向某個派生類的對象,既不會破壞代碼的正確性,也不須要改變已有代碼。

    不要經過公用繼承重用代碼,公用繼承是爲了被重用的。

 

第38條 實施安全的改寫

    改寫一個虛擬函數時,應該保持可替換性,就是要保持基類中函數的先後條件。不要改變虛擬函數的默認參數。

 

第39條 考慮將虛擬函數聲明爲非公用的,將公用函數聲明爲非虛擬的

    在基類中進行修改代碼代價高昂(尤爲是庫中和框架中的基類):請將公用函數設爲非虛擬的。應該將虛擬函數設爲私有的,或者若是派生類須要調用基類版本,則設爲保護的。(不適用於析構函數)

 

第40條 要避免提供隱式轉換

    隱式轉換會在最意料不到的地方拋出異常;並不老是能與語言的其餘元素有效的配合。儘可能使用顯式轉換。

 

第41條 將數據成員設爲私有的,無行爲的彙集(C語言形式的struct)除外

    要避免將公用數據和非公用數據混合在一塊兒。擁有公用數據意味着類的部分狀態的變化多是沒法控制的、沒法預測的、與其餘狀態異步發生的。

 

第42條 不要公開內部數據

    避免返回類所管理的內部數據的句柄,這樣類的客戶就不會不受控制的修改對象本身擁有的狀態。

    數據隱藏是一種強大的抽象方式,也是強大的模塊化機制。

 

第43條 明智地使用Pimpl

    若是建立「編譯器防火牆」將調用代碼與類的私有部分徹底隔離是明智的,就應該使用Pimpl慣用法:將私有部分隱藏在一個不透明的指針(即指向已經聲明可是還沒有定義的類的指針,最好是選擇合適的智能指針)後面。

 

第44條 優先編寫非成員非友元函數

    非成員非友元函數經過儘可能減小依賴提升了封裝性:函數體不能依賴於類的非公用成員。

 

第45條 老是一塊兒提供new和delete

 

第46條 若是提供類專門的new,應該提供全部標準形式(普通、就地和不拋出)

 

構造、析構與複製

 

第47條 以一樣的順序定義和初始化成員變量

    成員變量初始化的順序要與類定義中聲明的順序始終保持一致;不用考慮構造函數初始化列表中編寫的順序。要確保構造函數代碼不會致使混淆地指定不一樣的順序。

    C++語言之因此採起這樣的設計,是由於要確保銷燬成員的順序是惟一的;不然,析構函數將以不一樣順序銷燬對象,具體順序取決於構造對象的構造函數。

 

第48條 在構造函數中用初始化代替賦值

    在初始化列表中初始化成員變量,代碼表達意圖更加明確,代碼一般還會更小、更快。A():s1_(「hello」), s2_(「world」){}

 

第49條 避免在構造函數和析構函數中調用虛擬函數

 

第50條 將基類析構函數設爲公用且虛擬的,或者保護且非虛擬的

 

第51條 析構函數、釋放和交換絕對不能失敗

 

第52條 一致地進行復制和銷燬

    若是定義了複製構造函數、複製賦值操做符或者析構函數中的任何一個,那麼也須要定義另外兩個。

 

第53條 顯式地啓用或者禁止複製

    要清醒的知道本身選擇什麼樣的行爲:是使用編譯器生成的默認複製構造函數和賦值操做符;仍是編寫本身的版本;或者若是不容許複製的話,顯式地禁用前兩種方式。

 

第54條 避免切片。在基類中考慮用克隆代替複製

    在基類中,若是客戶須要進行多態(完整的、深度的)複製的話,考慮禁止複製構造函數和複製賦值操做符而改成提供虛擬的Clone成員函數。

 

第55條 使用賦值的標準形式

 

第56條 只要可行,就提供不會失敗的swap(並且要正確地提供)

 


名字空間與模塊

第57條 將類型及其非成員函數接口置於同一名字空間中

    非成員也是函數:若是要將非成員函數(特別是操做符和輔助函數)設計成類X的接口的一部分,那麼就必須與X相同的名字空間中定義它們,以便正確調用。

 

第58條 應該將類型和函數分別置於不一樣的名字空間中,除非有意想讓它們一塊兒工做

 

第59條 不要在頭文件中或者#include以前編寫名字空間using

    不要在#include以前編寫using指令;

    頭文件中,不要編寫名字空間級的using指令或using聲明,應該顯式的用名字空間限定全部的名字。

 

第60條 要避免在不一樣的模塊中分配和釋放內存

    在一個模塊中分配內存,而在另外一個模塊中釋放它,會在這兩個模塊之間產生微妙的遠距離依賴使程序變得脆弱。

 

第61條 不要在頭文件中定義具備連接的實體

    具備連接的實體,包括名字空間級的變量或函數,都須要分配內存。在頭文件中定義這樣的實體將致使連接時錯誤或者內存的浪費。應將全部具備連接的實體放入實現文件。

 

第62條 不要容許異常跨越模塊邊界傳播

    C++異常處理沒有廣泛通用的二進制標準。不要在兩段代碼之間傳播異常,除非可以控制用來構建兩段代碼的編譯器和編譯選項;不然模塊可能沒法支持可兼容地實現異常傳播。

 

第63條 在模塊的接口中使用具備良好可移植性的類型

 

模板與泛型

第64條 理智地結合靜態多態性和動態多態性

第65條 有意地進行顯式自定義

    編寫模板時,應該有意地、正確地提供自定義點,並清晰地記入文檔。在使用模板時,應該瞭解模板想要你如何進行自定義以將其用於你的類型,而且正確地自定義。

 

第66條 不要特化函數模板

 

第67條 不要無心地編寫不通用的代碼

    依賴抽象而非細節:使用最通用、最抽象的方法來實現一個功能。


錯誤處理與異常
第68條 普遍地使用斷言記錄內部假設和不變式

     一個事件中所含的信息量與該事件發生的機率是成反比的。若是assert觸發的可能性越低,它觸發時所提供的信息量就越大。儘可能使用assert(!」informational message」)。

 

第69條 創建合理的錯誤處理策略,並嚴格遵照

    應該在設計早期開發實際、一致、合理的錯誤處理策略,並予以嚴格遵照。策略必須包含:

    鑑別:哪些狀況屬於錯誤

    嚴重程度:每一個錯誤的嚴重性或緊急性

    檢查:哪些代碼負責檢查錯誤

    傳遞:用什麼機制在模塊中報告和傳遞錯誤通知

    處理:哪些代碼負責處理錯誤

    報告:怎樣將錯誤記入日誌,或通知用戶

只在模塊邊界處改變錯誤處理機制。

 

第70條 區別錯誤與非錯誤

    錯誤就是阻止函數成功操做的任何失敗。

 

第71條 設計和編寫錯誤安全代碼

 

第72條 優先使用異常報告錯誤

    出現問題時,就使用異常:應該使用異常而不是錯誤碼來報告錯誤。

    異常處理很天然地將錯誤檢查和恢復都放進了獨立的catch代碼塊,使錯誤處理變得清晰有形。

 

第73條 經過值拋出,經過引用捕獲

    經過值(而非指針)拋出異常,經過引用(一般是const的引用)捕獲異常。從新拋出相同的異常時,優先使用throw,避免使用throw e;。

 

第74條 正確地報告、處理和轉換錯誤

 

第75條 避免使用異常規範

 

STL:容器

第76條 默認時使用vector。不然,選擇其餘合適的容器

    意思就是,在使用數組、鏈表等數據結構時,優先使用標準庫;而後選擇你認爲的最好的容器便可。

 

第77條 用vector和string代替數組

    不要使用C語言風格的數組、指針運算和內存管理原語操做實現數組抽象。使用vector或者string不只更輕鬆,並且還有助於編寫更安全、伸縮性更好的軟件。

 

第78條 使用vector(和string::c_str)與非C++ API交換數據

 

第79條 在容器中只存儲值和智能指針

    在容器中存儲值對象:容器假設他們所存放的是相似值的類型,包括值類型、智能指針和迭代器。

 

第80條 用push_back代替其餘擴展序列的方式

 

第81條 多用範圍操做,少用單元素操做

    調用範圍操做一般更易於編寫,也更易於閱讀,並且比顯式循環的效率更高。

 

第82條 使用公認的慣用法真正地壓縮容量,真正地刪除元素

    要真正地壓縮容器的多餘容量,應該使用「swap魔術」慣用法。要真正地刪除容器中的元素,應該使用erase-remove慣用法。

 

STL:算法
第83條 使用帶檢查的STL實現

 

第84條 用算法調用代替手工編寫的循環

    編寫算法調用代替手工編寫的循環,可使表達力更強、維護性更好、更不易出錯,並且一樣高效。

    算法的正確性也極可能比循環好。手工編寫的循環很容易犯使用無效迭代器這樣的錯誤。

    算法的效率常常比原始循環要好。咱們所使用的標準算法是由實現標準容器的那些人實現的,就憑他們對內幕的瞭解,所編寫的算法的效率,就絕非你我編寫的任何版本所能相提並論。可是最重要的還在於,許多算法的實現精巧絕倫,你我這樣的一線程序員手工編寫的代碼也是不可能與之一較短長的。

 

第85條 使用正確的STL查找算法

    正確的查找方式應該使用STL(雖然比光速慢,但已經很是快了)。

    查找無序範圍,應使用find/find_if或者count/count_if。查找有序範圍,應使用lower_bound/upper_bound/equal_range或binary_search。

 

第86條 使用正確的STL排序算法

 

第87條 使謂詞成爲純函數

    保持謂詞純潔性:謂詞就是返回是或否的函數對象。

    不要讓謂詞保存或訪問對其operator()結果有影響的狀態,包括成員狀態和全局狀態。應該使operator()成爲謂詞的const成員函數。

 

第88條 算法和比較器的參數應多用函數對象少用函數

    對象的適配性比函數好:應該向算法傳遞函數對象,而非函數。關聯容器的比較器必須是函數對象。函數對象的適配性好,並且與直覺相反,他們產生的代碼通常比函數要快。

 

第89條 正確編寫函數對象

    函數對象模仿的就是函數指針。與函數指針同樣,通常函數對象應該經過值來傳遞。全部標準算法都是經過值來傳遞對象的,咱們本身的算法也應如此。

 

類型安全

 

第90條 避免使用類型分支,多使用多態

    避免經過對象類型分支來定製行爲。使用模板和虛函數,讓類型本身來決定行爲。

 

第91條 依賴類型,而非其表示方式

 

第92條 避免使用reinterpret_cast

    不要嘗試使用reinterpret_cast強制編譯器將某個類型對象的內存表示從新解釋成另外一種類型的對象。這違反了維護類型安全性的原則,尤爲可怕的是,reinterpret_cast甚至不能保證是否可以達到這一目的,也沒法保證其餘功能。

 

第93條 避免對指針使用static_cast

    不要對動態對象的指針使用static_cast:安全的替代方法有不少,包括使用dynamic_cast,重構,乃至從新設計。

 

第94條 避免強制轉換const

     強制轉換有時會致使未定義的行爲,即便合法,也是不良的編程風格的主要表現。 

 

第95條 不要使用C風格的強制轉換

    C語言風格的強制轉換根據上下文具備不一樣的語義,而全部這些都隱藏在相同的語法背後。用C++風格的強制轉換代替C風格的強制轉換有助於防範意想不到的錯誤。

 

第96條 不要對非POD進行memcpy操做或者memcmp操做

 

第97條 不要使用聯合從新解釋表示方式

 

第98條 不要使用可變長參數(...)

    要避免使用可變長參數,應改用高級的C++結構和庫。

 

第99條 不要使用失效對象。不要使用不安全函數

 

第100條 不要多態地處理數組

   數組的可調整性不好:多態地處理數組是絕對的類型錯誤,並且編譯器有可能不會作出任何提示。

相關文章
相關標籤/搜索