建設(shè)政府網(wǎng)站的目的意義百度推廣每年600元什么費(fèi)用
目錄
谷歌C++風(fēng)格指南:https://zh-google-styleguide.readthedocs.io/en/latest/google-cpp-styleguide/contents/
編碼規(guī)則:
? 開閉原則:軟件對(duì)擴(kuò)展是開放的,對(duì)修改是關(guān)閉的
? 防御式編程:簡(jiǎn)單的說就是程序不能崩潰
? 里氏代換原則:子類型必須能夠替代他們的基類型
頭文件:
? self-contained頭文件: 用來插入文本的文件,說到底它們并不是頭文件,所以應(yīng)以 .inc 結(jié)尾——?
? define保護(hù):所有頭文件都應(yīng)該使用 #define 來防止頭文件被多重包含, 命名格式當(dāng)是:
#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
…
#endif // FOO_BAR_BAZ_H_
? 前置聲明:?盡可能地避免使用前置聲明。使用?#include?包含需要的頭文件即可。
○ 優(yōu)點(diǎn):
§ 前置聲明能夠節(jié)省編譯時(shí)間,多余的?#include?會(huì)迫使編譯器展開更多的文件,處理更多的輸入。
§ 前置聲明能夠節(jié)省不必要的重新編譯的時(shí)間。?#include?使代碼因?yàn)轭^文件中無(wú)關(guān)的改動(dòng)而被重新編譯多次?!欣斜?#xff0c;如下面的缺點(diǎn)
○ 缺點(diǎn):
§ 前置聲明隱藏了依賴關(guān)系,頭文件改動(dòng)時(shí),用戶的代碼會(huì)跳過必要的重新編譯過程。
§ 前置聲明可能會(huì)被庫(kù)的后續(xù)更改所破壞。前置聲明函數(shù)或模板有時(shí)會(huì)妨礙頭文件開發(fā)者變動(dòng)其 API. 例如擴(kuò)大形參類型,加個(gè)自帶默認(rèn)參數(shù)的模板形參等等。
§ 很難判斷什么時(shí)候該用前置聲明,什么時(shí)候該用?#include
§ 前置聲明了不少來自頭文件的 symbol 時(shí),就會(huì)比單單一行的?include?冗長(zhǎng)。
? 內(nèi)聯(lián)函數(shù):
○ 不要內(nèi)聯(lián)超過 10 行的函數(shù). 謹(jǐn)慎對(duì)待析構(gòu)函數(shù), 析構(gòu)函數(shù)往往比其表面看起來要更長(zhǎng), 因?yàn)橛须[含的成員和基類析構(gòu)函數(shù)被調(diào)用
○ 內(nèi)聯(lián)那些包含循環(huán)或?switch?語(yǔ)句的函數(shù)常常是得不償失——?
○ 有些函數(shù)即使聲明為內(nèi)聯(lián)的也不一定會(huì)被編譯器內(nèi)聯(lián), 這點(diǎn)很重要; 比如虛函數(shù)和遞歸函數(shù)就不會(huì)被正常內(nèi)聯(lián). 通常, 遞歸函數(shù)不應(yīng)該聲明成內(nèi)聯(lián)函數(shù)
? #include路徑次序如下:
1. dir2/foo2.h (優(yōu)先位置, 詳情如下)
2. C 系統(tǒng)文件
3. C++ 系統(tǒng)文件
4. 其他庫(kù)的 .h 文件
5. 本項(xiàng)目?jī)?nèi) .h 文件
作用域:
? 局部變量:?在盡可能小的作用域中聲明變量, 離第一次使用越近越好;?應(yīng)使用初始化的方式替代聲明再賦值,?有一個(gè)例外, 在循環(huán)作用域中,如果變量是一個(gè)對(duì)象, 每次進(jìn)入作用域都要調(diào)用其構(gòu)造函數(shù), 每次退出作用域都要調(diào)用其析構(gòu)函數(shù). 這會(huì)導(dǎo)致效率降低.
? 匿名命名空間和靜態(tài)變量:?所有置于匿名命名空間的聲明都具有內(nèi)部鏈接性,函數(shù)和變量可以經(jīng)由聲明為?static?擁有內(nèi)部鏈接性,這意味著你在這個(gè)文件中聲明的這些標(biāo)識(shí)符都不能在另一個(gè)文件中被訪問。即使兩個(gè)文件聲明了完全一樣名字的標(biāo)識(shí)符,它們所指向的實(shí)體實(shí)際上是完全不同的。結(jié)論是:?推薦、鼓勵(lì)在?.cc?中對(duì)于不需要在其他地方引用的標(biāo)識(shí)符使用內(nèi)部鏈接性聲明,但是不要在?.h?中使用。
? 非成員函數(shù),靜態(tài)成員函數(shù)和全局函數(shù):
○ 使用靜態(tài)成員函數(shù)或命名空間內(nèi)的非成員函數(shù), 盡量不要用裸的全局函數(shù).
○ 將一系列函數(shù)直接置于命名空間中,不要用類的靜態(tài)方法模擬出命名空間的效果(?),類的靜態(tài)方法應(yīng)當(dāng)和類的實(shí)例或靜態(tài)數(shù)據(jù)緊密相關(guān).
○ 所以如果必須定義非成員函數(shù), 又只是在?.cc?文件中使用它, 可使用匿名?命名空間?或?static?鏈接關(guān)鍵字 (如?static?int?Foo()?{…}) 限定其作用域.
// 應(yīng)為:
namespace myproject {
namespace foo_bar {
void Function1();
void Function2();
}??// namespace foo_bar
}??// namespace myproject
// 而非:
namespace myproject {
class FooBar {
public:
??static void Function1();
??static void Function2();};
}??// namespace myproject
? 靜態(tài)和全局變量:
○ 靜態(tài)生存?周期的對(duì)象,即包括了全局變量,靜態(tài)變量,靜態(tài)類成員變量和函數(shù)靜態(tài)變量,都必須是原生數(shù)據(jù)類型 (POD : Plain Old Data): 即 int, char 和 float, 以及 POD 類型的指針、數(shù)組和結(jié)構(gòu)體
○ 靜態(tài)變量的構(gòu)造函數(shù)、析構(gòu)函數(shù)和初始化的順序在 C++ 中是只有部分明確的,甚至隨著構(gòu)建變化而變化,導(dǎo)致難以發(fā)現(xiàn)的 bug. 所以除了禁用類類型的全局變量,我們也不允許用函數(shù)返回值來初始化 POD 變量,除非該函數(shù)(如 getenv() 或 getpid() )不涉及任何全局變量。函數(shù)作用域里的靜態(tài)變量除外,畢竟它的初始化順序是有明確定義的,而且只會(huì)在指令執(zhí)行到它的聲明那里才會(huì)發(fā)生。( 同一個(gè)編譯單元內(nèi)是明確的,靜態(tài)初始化優(yōu)先于動(dòng)態(tài)初始化,初始化順序按照聲明順序進(jìn)行,銷毀則逆序。不同的編譯單元之間初始化和銷毀順序?qū)儆谖疵鞔_行為) 同理,全局和靜態(tài)變量在程序中斷時(shí)會(huì)被析構(gòu),無(wú)論所謂中斷是從 main() 返回還是對(duì) exit() 的調(diào)用。析構(gòu)順序正好與構(gòu)造函數(shù)調(diào)用的順序相反。但既然構(gòu)造順序未定義,那么析構(gòu)順序當(dāng)然也就不定了。 綜上所述,我們只允許 POD 類型的靜態(tài)變量,即完全禁用 vector (使用 C 數(shù)組替代) 和 string (使用 const char [])。 如果您確實(shí)需要一個(gè) class 類型的靜態(tài)或全局變量,可以考慮在 main() 函數(shù)或 pthread_once() 內(nèi)初始化一個(gè)指針且永不回收。注意只能用 raw 指針,別用智能指針,畢竟后者的析構(gòu)函數(shù)涉及到上文指出的不定順序問題。
函數(shù):
? 參數(shù)順序:輸入?yún)?shù)在先,后跟輸出參數(shù)。?在加入新參數(shù)時(shí)不要因?yàn)樗鼈兪切聟?shù)就置于參數(shù)列表最后, 而是仍然要按照前述的規(guī)則
? 編寫簡(jiǎn)短, 凝練的函數(shù),??如果函數(shù)超過 40 行, 可以思索一下能不能在不影響程序結(jié)構(gòu)的前提下對(duì)其進(jìn)行分割
? 所有按引用傳遞的參數(shù)必須加上?const。事實(shí)上這在 Google Code 是一個(gè)硬性約定: 輸入?yún)?shù)是值參或?const?引用, 輸出參數(shù)為指針. 輸入?yún)?shù)可以是?const?指針, 但決不能是非?const?的引用參數(shù), 除非特殊要求, 比如?swap().——這是為什么?
? 缺省參數(shù):?只允許在非虛函數(shù)中使用缺省參數(shù), 且必須保證缺省參數(shù)的值始終一致。?對(duì)于虛函數(shù), 不允許使用缺省參數(shù), 因?yàn)樵谔摵瘮?shù)中缺省參數(shù)不一定能正常工作.
類:
? 構(gòu)造函數(shù)的職責(zé):不要在構(gòu)造函數(shù)中調(diào)用虛函數(shù), 也不要在無(wú)法報(bào)出錯(cuò)誤時(shí)進(jìn)行可能失敗的初始化.
1. 缺點(diǎn):
1. 在沒有使程序崩潰 (因?yàn)椴⒉皇且粋€(gè)始終合適的方法) 或者使用異常 (因?yàn)橐呀?jīng)被?禁用?了) 等方法的條件下, 構(gòu)造函數(shù)很難上報(bào)錯(cuò)誤
2. 如果執(zhí)行失敗, 會(huì)得到一個(gè)初始化失敗的對(duì)象, 這個(gè)對(duì)象有可能進(jìn)入不正常的狀態(tài), 必須使用?bool?IsValid()?或類似這樣的機(jī)制才能檢查出來, 然而這是一個(gè)十分容易被疏忽的方法.
3. 構(gòu)造函數(shù)的地址是無(wú)法被取得的, 因此, 舉例來說, 由構(gòu)造函數(shù)完成的工作是無(wú)法以簡(jiǎn)單的方式交給其他線程的.
2. 結(jié)論:?構(gòu)造函數(shù)不允許調(diào)用虛函數(shù). 如果代碼允許, 直接終止程序是一個(gè)合適的處理錯(cuò)誤的方式. 否則, 考慮用?Init()?方法或工廠函數(shù).
? 隱式類型轉(zhuǎn)換:?不要定義隱式類型轉(zhuǎn)換. 對(duì)于轉(zhuǎn)換運(yùn)算符和單參數(shù)構(gòu)造函數(shù), 請(qǐng)使用?explicit?關(guān)鍵字.
○ 用法:?explicit?關(guān)鍵字可以用于構(gòu)造函數(shù)或 (在 C++11 引入) 類型轉(zhuǎn)換運(yùn)算符, 以保證只有當(dāng)目的類型在調(diào)用點(diǎn)被顯式寫明時(shí)才能進(jìn)行類型轉(zhuǎn)換
○ 結(jié)論:?在類型定義中, 類型轉(zhuǎn)換運(yùn)算符和單參數(shù)構(gòu)造函數(shù)都應(yīng)當(dāng)用?explicit?進(jìn)行標(biāo)記. 一個(gè)例外是, 拷貝和移動(dòng)構(gòu)造函數(shù)不應(yīng)當(dāng)被標(biāo)記為?explicit, 因?yàn)樗鼈儾⒉粓?zhí)行類型轉(zhuǎn)換。?不能以一個(gè)參數(shù)進(jìn)行調(diào)用的構(gòu)造函數(shù)不應(yīng)當(dāng)加上?explicit. 接受一個(gè)?std::initializer_list?作為參數(shù)的構(gòu)造函數(shù)也應(yīng)當(dāng)省略?explicit, 以便支持拷貝初始化 (例如?MyType?m?=?{1,?2}😉?.
? 可拷貝類型和可移動(dòng)類型:
○ 如果類型需要, 就讓它們支持拷貝 / 移動(dòng). 否則, 就把隱式產(chǎn)生的拷貝和移動(dòng)函數(shù)禁用.
? struct vs class:?僅當(dāng)只有數(shù)據(jù)成員時(shí)使用?struct, 其它一概使用?class.??struct?用來定義包含數(shù)據(jù)的被動(dòng)式對(duì)象, 也可以包含相關(guān)的常量
? 繼承:?使用組合常常比使用繼承更合理. 如果使用繼承的話, 定義為?public?繼承.
? 多重繼承:真正用到多重繼承的情況少之又少;只有在以下情況下才允許使用多重繼承:最多只有一個(gè)基類是非抽象類;其他基類都是以??Interface?為后綴的純接口類;
○ 結(jié)論:只有當(dāng)所有父類除第一個(gè)外都是?純接口類?時(shí), 才允許使用多重繼承. 為確保它們是純接口, 這些類必須以?Interface?為后綴.
? 接口:
? 運(yùn)算符重載:?除少數(shù)特定環(huán)境外, 不要重載運(yùn)算符. 也不要?jiǎng)?chuàng)建用戶定義字面量。?不要重載?&&,?||,?,?或一元運(yùn)算符?&. 不要重載?operator"", 也就是說, 不要引入用戶定義字面量.
? 存取控制:?將?所有?數(shù)據(jù)成員聲明為?private, 除非是?static?const?類型成員
? 聲明順序:?將相似的聲明放在一起, 將?public?部分放在最前。說明:
○ 類定義一般應(yīng)以?public:?開始, 后跟?protected:, 最后是?private:. 省略空部分.
○ 在各個(gè)部分中, 建議將類似的聲明放在一起, 并且建議以如下的順序: 類型 (包括?typedef,?using?和嵌套的結(jié)構(gòu)體與類), 常量, 工廠函數(shù), 構(gòu)造函數(shù), 賦值運(yùn)算符, 析構(gòu)函數(shù), 其它函數(shù), 數(shù)據(jù)成員.
其他C++特性:
? 右值引用:只在定義移動(dòng)構(gòu)造函數(shù)與移動(dòng)賦值操作時(shí)使用右值引用. 不要使用?std::forward.
○ 缺點(diǎn):?右值引用是一個(gè)相對(duì)比較新的特性 (由 C++11 引入), 它尚未被廣泛理解. 類似引用崩潰, 移動(dòng)構(gòu)造函數(shù)的自動(dòng)推導(dǎo)這樣的規(guī)則都是很復(fù)雜的.
? 盡量不使用函數(shù)重載
? 異常:不使用異常;對(duì)于到底需不需要使用異常,參考:?https://www.zhihu.com/question/22889420
○ 優(yōu)點(diǎn):
§ 異常是處理構(gòu)造函數(shù)失敗的唯一途徑
§ 有些第三方庫(kù)依賴異常,禁用異常就不好用了
§ 在測(cè)試框架很有用
○ 缺點(diǎn)(還需整理)
§ 在現(xiàn)有函數(shù)中添加?throw?語(yǔ)句時(shí),必須檢查所有調(diào)用點(diǎn)。要么讓所有調(diào)用點(diǎn)統(tǒng)統(tǒng)具備最低限度的異常安全保證,要么眼睜睜地看異常一路歡快地往上跑,最終中斷掉整個(gè)程序。舉例,f()?調(diào)用?g(),?g()?又調(diào)用?h(), 且?h?拋出的異常被?f?捕獲。當(dāng)心?g, 否則會(huì)沒妥善清理好。
§ 還有更常見的,異常會(huì)徹底擾亂程序的執(zhí)行流程并難以判斷,函數(shù)也許會(huì)在您意料不到的地方返回。您或許會(huì)加一大堆何時(shí)何處處理異常的規(guī)定來降低風(fēng)險(xiǎn),然而開發(fā)者的記憶負(fù)擔(dān)更重了。
§ 異常安全需要RAII和不同的編碼實(shí)踐. 要輕松編寫出正確的異常安全代碼需要大量的支持機(jī)制. 更進(jìn)一步地說, 為了避免讀者理解整個(gè)調(diào)用表, 異常安全必須隔絕從持續(xù)狀態(tài)寫到 “提交” 狀態(tài)的邏輯. 這一點(diǎn)有利有弊 (因?yàn)槟阋苍S不得不為了隔離提交而混淆代碼). 如果允許使用異常, 我們就不得不時(shí)刻關(guān)注這樣的弊端, 即使有時(shí)它們并不值得.
§ 啟用異常會(huì)增加二進(jìn)制文件數(shù)據(jù),延長(zhǎng)編譯時(shí)間(或許影響小),還可能加大地址空間的壓力。
§ 濫用異常會(huì)變相鼓勵(lì)開發(fā)者去捕捉不合時(shí)宜,或本來就已經(jīng)沒法恢復(fù)的「?jìng)萎惓!?。比?#xff0c;用戶的輸入不符合格式要求時(shí),也用不著拋異常。如此之類的偽異常列都列不完。
? 運(yùn)行時(shí)類型識(shí)別:?RTTI 允許程序員在運(yùn)行時(shí)識(shí)別 C++ 類對(duì)象的類型. 它通過使用?typeid?或者?dynamic_cast?完成.
○ 優(yōu)點(diǎn):?RTTI 在某些單元測(cè)試中非常有用. 比如進(jìn)行工廠類測(cè)試時(shí), 用來驗(yàn)證一個(gè)新建對(duì)象是否為期望的動(dòng)態(tài)類型. RTTI 對(duì)于管理對(duì)象和派生對(duì)象的關(guān)系也很有用.
○ 缺點(diǎn):
§ 在運(yùn)行時(shí)判斷類型通常意味著設(shè)計(jì)問題. 如果你需要在運(yùn)行期間確定一個(gè)對(duì)象的類型, 這通常說明你需要考慮重新設(shè)計(jì)你的類.
§ 隨意地使用 RTTI 會(huì)使你的代碼難以維護(hù). 它使得基于類型的判斷樹或者 switch 語(yǔ)句散布在代碼各處. 如果以后要進(jìn)行修改, 你就必須檢查它們.
○ 結(jié)論:RTTI 有合理的用途但是容易被濫用, 因此在使用時(shí)請(qǐng)務(wù)必注意. 在單元測(cè)試中可以使用 RTTI, 但是在其他代碼中請(qǐng)盡量避免. 尤其是在新代碼中, 使用 RTTI 前務(wù)必三思. 如果你的代碼需要根據(jù)不同的對(duì)象類型執(zhí)行不同的行為的話, 請(qǐng)考慮用以下的兩種替代方案之一查詢類型:?
§ *虛函數(shù)可以根據(jù)子類類型的不同而執(zhí)行不同代碼. 這是把工作交給了對(duì)象本身去處理.
§ 如果這一工作需要在對(duì)象之外完成, 可以考慮使用雙重分發(fā)的方案, 例如使用訪問者設(shè)計(jì)模式. 這就能夠在對(duì)象之外進(jìn)行類型判斷.
§ 如果程序能夠保證給定的基類實(shí)例實(shí)際上都是某個(gè)派生類的實(shí)例, 那么就可以自由使用 dynamic_cast. 在這種情況下, 使用 dynamic_cast 也是一種替代方案.
§ 注意:基于類型的判斷樹是一個(gè)很強(qiáng)的暗示, 它說明你的代碼已經(jīng)偏離正軌了. 不要像下面這樣:
if (typeid(*data) == typeid(D1)) {
…} else if (typeid(*data) == typeid(D2)) {
…} else if (typeid(*data) == typeid(D3)) {…
○ 一旦在類層級(jí)中加入新的子類, 像這樣的代碼往往會(huì)崩潰. 而且, 一旦某個(gè)子類的屬性改變了, 你很難找到并修改所有受影響的代碼塊。不要去手工實(shí)現(xiàn)一個(gè)類似 RTTI 的方案. 反對(duì) RTTI 的理由同樣適用于這些方案, 比如帶類型標(biāo)簽的類繼承體系. 而且, 這些方案會(huì)掩蓋你的真實(shí)意圖.
? 類型轉(zhuǎn)換:?使用 C++ 的類型轉(zhuǎn)換, 如?static_cast<>(). 不要使用?int?y?=?(int)x?或?int?y?=?int(x)?等轉(zhuǎn)換方式
○ 優(yōu)點(diǎn):?C 語(yǔ)言的類型轉(zhuǎn)換問題在于模棱兩可的操作; 有時(shí)是在做強(qiáng)制轉(zhuǎn)換 (如?(int)3.5), 有時(shí)是在做類型轉(zhuǎn)(如?(int)“hello”). 另外, C++ 的類型轉(zhuǎn)換在查找時(shí)更醒目——?難道第一個(gè)不是強(qiáng)制類型轉(zhuǎn)換
○ 結(jié)論:
§ 用?static_cast?替代 C 風(fēng)格的值轉(zhuǎn)換, 或某個(gè)類指針需要明確的向上轉(zhuǎn)換為父類指針時(shí).
§ 用?const_cast?去掉?const?限定符.
§ 用?reinterpret_cast?指針類型和整型或其它指針之間進(jìn)行不安全的相互轉(zhuǎn)換. 僅在你對(duì)所做一切了然于心時(shí)使用.
? 流:?只在記錄日志時(shí)使用流.?流用來替代?printf()?和?scanf().——?不只是這兩個(gè)吧,文件流,string流…
○ 優(yōu)點(diǎn):?有了流, 在打印時(shí)不需要關(guān)心對(duì)象的類型. 不用擔(dān)心格式化字符串與參數(shù)列表不匹配 (雖然在 gcc 中使用?printf?也不存在這個(gè)問題). 流的構(gòu)造和析構(gòu)函數(shù)會(huì)自動(dòng)打開和關(guān)閉對(duì)應(yīng)的文件.
○ 缺點(diǎn):流使得?pread()?等功能函數(shù)很難執(zhí)行. 如果不使用?printf?風(fēng)格的格式化字符串, 某些格式化操作 (尤其是常用的格式字符串?%.*s) 用流處理性能是很低的. 流不支持字符串操作符重新排序 (%1s), 而這一點(diǎn)對(duì)于軟件國(guó)際化很有用.——?
○ 結(jié)論:?不要使用流, 除非是日志接口需要. 使用?printf?+?read/write之類的代替.——主要還是從可讀性,易出錯(cuò)性等方面來說的
? 前置自增/自減:?對(duì)簡(jiǎn)單數(shù)值 (非對(duì)象), 兩種都無(wú)所謂. 對(duì)迭代器和模板類型, 使用前置自增 (自減).
? const:
○ 缺點(diǎn):?const?是入侵性的: 如果你向一個(gè)函數(shù)傳入?const?變量, 函數(shù)原型聲明中也必須對(duì)應(yīng)?const?參數(shù) (否則變量需要?const_cast?類型轉(zhuǎn)換), 在調(diào)用庫(kù)函數(shù)時(shí)顯得尤其麻煩.
○ 結(jié)論:?const?變量, 數(shù)據(jù)成員, 函數(shù)和參數(shù)為編譯時(shí)類型檢測(cè)增加了一層保障; 便于盡早發(fā)現(xiàn)錯(cuò)誤. 因此強(qiáng)烈建議在任何可能的情況下使用?const,此外有時(shí)改用 C++11 推出的 constexpr 更好;?mutable?可以使用, 但是在多線程中是不安全的, 使用時(shí)首先要考慮線程安全.
? constexpr:?在 C++11 里,用 constexpr 來定義真正的常量,或?qū)崿F(xiàn)常量初始化。?變量可以被聲明成 constexpr 以表示它是真正意義上的常量,即在編譯時(shí)和運(yùn)行時(shí)都不變。函數(shù)或構(gòu)造函數(shù)也可以被聲明成 constexpr, 以用來定義 constexpr 變量。
○ 結(jié)論:?靠 constexpr 特性,方才實(shí)現(xiàn)了 C++ 在接口上打造真正常量機(jī)制的可能。好好用 constexpr 來定義真常量以及支持常量的函數(shù)。避免復(fù)雜的函數(shù)定義,以使其能夠與constexpr一起使用。 千萬(wàn)別癡心妄想地想靠 constexpr 來強(qiáng)制代碼「內(nèi)聯(lián)」。
? 整型:?<stdint.h>?定義了?int16_t,?uint32_t,?int64_t?等整型, 在需要確保整型大小時(shí)可以使用它們代替?short,?unsigned?long?long?等. 在 C 整型中, 只使用?int. 在合適的情況下, 推薦使用標(biāo)準(zhǔn)類型如?size_t?和?ptrdiff_t.對(duì)于大整數(shù), 使用?int64_t.不要使用?uint32_t?等無(wú)符號(hào)整型, 除非你是在表示一個(gè)位組而不是一個(gè)數(shù)值, 或是你需要定義二進(jìn)制補(bǔ)碼溢出. 尤其是不要為了指出數(shù)值永不會(huì)為負(fù), 而使用無(wú)符號(hào)類型. 相反, 你應(yīng)該使用斷言來保護(hù)數(shù)據(jù).
? 64位下的可移植性
? 預(yù)處理宏:?使用宏時(shí)要非常謹(jǐn)慎, 盡量以內(nèi)聯(lián)函數(shù), 枚舉和常量代替之.如果你要宏, 盡可能遵守:
○ 不要在?.h?文件中定義宏.
○ 在馬上要使用時(shí)才進(jìn)行?#define, 使用后要立即?#undef.
○ 不要只是對(duì)已經(jīng)存在的宏使用#undef,選擇一個(gè)不會(huì)沖突的名稱;
○ 不要試圖使用展開后會(huì)導(dǎo)致 C++ 構(gòu)造不穩(wěn)定的宏, 不然也至少要附上文檔說明其行為.
○ 不要用?##?處理函數(shù),類和變量的名字。
? nullptr和NULL:?整數(shù)用?0, 實(shí)數(shù)用?0.0, 指針用?nullptr?或?NULL, 字符 (串) 用?‘\0’.
? sizeof:?盡可能用?sizeof(varname)?代替?sizeof(type).?使用?sizeof(varname)?是因?yàn)楫?dāng)代碼中變量類型改變時(shí)會(huì)自動(dòng)更新——?這個(gè)解釋怎么理解?
? auto:??可以用?auto?來復(fù)制初始化或綁定引用——??auto 在涉及迭代器的循環(huán)語(yǔ)句里挺常用
○ 只在局部變量里用,別用在文件作用域變量,命名空間作用域變量和類數(shù)據(jù)成員里。永遠(yuǎn)別列表初始化?auto?變量。
○ auto?還可以和 C++11 特性「尾置返回類型(trailing return type)」一起用,不過后者只能用在 lambda 表達(dá)式里。
auto x(3);??// 圓括號(hào)。?? ?它們不是同一回事——x 是 int
auto y{3};??// 大括號(hào)。?? ?y 則是 std::initializer_list.
? lambda表達(dá)式:
○ 優(yōu)點(diǎn):
§ 傳函數(shù)對(duì)象給 STL 算法,Lambdas 最簡(jiǎn)易,可讀性也好。
§ Lambdas,?std::functions?和?std::bind?可以搭配成通用回調(diào)機(jī)制(general purpose callback mechanism);寫接收有界函數(shù)為參數(shù)的函數(shù)也很容易了?!?#xff1f;
○ 缺點(diǎn):
§ Lambdas 的變量捕獲略旁門左道,可能會(huì)造成懸空指針。
§ Lambdas 可能會(huì)失控;層層嵌套的匿名函數(shù)難以閱讀。
○ 結(jié)論:
§ 按 format 小用 lambda 表達(dá)式怡情。
§ 禁用默認(rèn)捕獲,捕獲都要顯式寫出來。比起?=?{return?x?+?n;}, 應(yīng)寫成?n?{return?x?+?n;}?才對(duì),這樣讀者也好一眼看出?n?是被捕獲的值。
§ 匿名函數(shù)始終要簡(jiǎn)短,如果函數(shù)體超過了五行,那么還不如起名(即把 lambda 表達(dá)式賦值給對(duì)象),或改用函數(shù)。
§ 如果可讀性更好,就顯式寫出 lambd 的尾置返回類型,就像auto.
? 模板編程:?除了優(yōu)點(diǎn)外,大量的使用模板編程接口會(huì)讓重構(gòu)工具(Visual Assist X, Refactor for C++等等)更難發(fā)揮用途. 首先模板的代碼會(huì)在很多上下文里面擴(kuò)展開來, 所以很難確認(rèn)重構(gòu)對(duì)所有的這些展開的代碼有用, 其次有些重構(gòu)工具只對(duì)已經(jīng)做過模板類型替換的代碼的AST 有用. 因此重構(gòu)工具對(duì)這些模板實(shí)現(xiàn)的原始代碼并不有效, 很難找出哪些需要重構(gòu).
○ 結(jié)論:模板編程最好只用在少量的基礎(chǔ)組件, 基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)上, 因?yàn)槟0鍘淼念~外的維護(hù)成本會(huì)被大量的使用給分擔(dān)掉
? boost庫(kù):?只使用 Boost 中被認(rèn)可的庫(kù):
命名約定:
? 文件命名:
○ 全部小寫,?可以包含下劃線 () 或連字符 (-), 依照項(xiàng)目的約定. 如果沒有約定, 那么 “” 更好.
○ C++ 文件要以?.cc?結(jié)尾, 頭文件以?.h?結(jié)尾. 專門插入文本的文件則以?.inc?結(jié)尾, 參見?頭文件自足
○ 定義類時(shí)文件名一般成對(duì)出現(xiàn),?如?foo_bar.h?和?foo_bar.cc, 對(duì)應(yīng)于類?FooBar.
○ 內(nèi)聯(lián)函數(shù)必須放在?.h?文件中. 如果內(nèi)聯(lián)函數(shù)比較短, 就直接放在?.h?中.——為什么是必須?
? 類型命名:?所有類型命名類, 結(jié)構(gòu)體, 類型定義 (typedef), 枚舉, 類型模板參數(shù) —— 均使用相同約定, 即以大寫字母開始, 每個(gè)單詞首字母均大寫, 不包含下劃線
? 變量命名:
○ 普通變量:?變量 (包括函數(shù)參數(shù)) 和數(shù)據(jù)成員名一律小寫, 單詞之間用下劃線連接
○ 類數(shù)據(jù)成員:?不管是靜態(tài)的還是非靜態(tài)的, 類數(shù)據(jù)成員都可以和普通變量一樣, 但要接下劃線.
○ 結(jié)構(gòu)體變量:不管是靜態(tài)的還是非靜態(tài)的, 結(jié)構(gòu)體數(shù)據(jù)成員都可以和普通變量一樣, 不用像類接下劃線
? 常量命名:?聲明為?constexpr?或?const?的變量, 或在程序運(yùn)行期間其值始終保持不變的, 命名時(shí)以 “k” 開頭, 大小寫混合,如const?int?kDaysInAWeek?=?7;?所有具有靜態(tài)存儲(chǔ)類型的變量 (例如靜態(tài)變量或全局變量) 都應(yīng)當(dāng)以此方式命名
? 函數(shù)命名:
○ 常規(guī)函數(shù)使用大小寫混合(即 “駝峰變量名” 或 “帕斯卡變量名”), 沒有下劃線. 對(duì)于首字母縮寫的單詞, 更傾向于將它們視作一個(gè)單詞進(jìn)行首字母大寫 (例如, 寫作?StartRpc()?而非?StartRPC()).
○ 取值和設(shè)值函數(shù)則要求與變量名匹配,?一般來說它們的名稱與實(shí)際的成員變量對(duì)應(yīng)?, 但并不強(qiáng)制要求
? 命名空間命名:?命名空間以小寫字母命名. 最高級(jí)命名空間的名字取決于項(xiàng)目名稱。命名空間中的代碼, 應(yīng)當(dāng)存放于和命名空間的名字匹配的文件夾或其子文件夾中.?注意?不使用縮寫作為名稱?的規(guī)則同樣適用于命名空間
? 枚舉命名:?枚舉的命名應(yīng)當(dāng)和?常量?或?宏?一致:?kEnumName?或是?ENUM_NAME.?單獨(dú)的枚舉值應(yīng)該優(yōu)先采用?常量?的命名方式
格式:
? 行長(zhǎng)度:?每一行代碼字符數(shù)不超過 80.
? 非ASCII字符:?盡量不使用非 ASCII 字符, 使用時(shí)必須使用 UTF-8 編碼.——這個(gè)怎么區(qū)分?
? 空格縮進(jìn)
? 函數(shù)聲明與定義
cpplint使用總結(jié):