, 則 auto v2(std::move(v1)) 將很可能不再進行大量的數(shù)據(jù)復(fù)制而只是簡單地進行指針操作, 在某些情況下這將帶來大幅度的性能提升." />
0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Google編程風格指南(四)

C語言專家集中營 ? 來源:未知 ? 作者:李倩 ? 2018-09-27 18:08 ? 次閱讀

6. 其他 C++ 特性

6.1. 引用參數(shù)

Tip

所有按引用傳遞的參數(shù)必須加上const.

定義:

在 C 語言中, 如果函數(shù)需要修改變量的值, 參數(shù)必須為指針, 如intfoo(int*pval). 在 C++ 中, 函數(shù)還可以聲明引用參數(shù):intfoo(int&val).

優(yōu)點:

定義引用參數(shù)防止出現(xiàn)(*pval)++這樣丑陋的代碼. 像拷貝構(gòu)造函數(shù)這樣的應(yīng)用也是必需的. 而且更明確, 不接受NULL指針.

缺點:

容易引起誤解, 因為引用在語法上是值變量卻擁有指針的語義.

結(jié)論:

函數(shù)參數(shù)列表中, 所有引用參數(shù)都必須是const:

void Foo(const string &in, string *out);

事實上這在 Google Code 是一個硬性約定: 輸入?yún)?shù)是值參或const引用, 輸出參數(shù)為指針. 輸入?yún)?shù)可以是const指針, 但決不能是非const的引用參數(shù),除非用于交換,比如swap().

有時候,在輸入形參中用constT*指針比constT&更明智。比如:

您會傳 null 指針。

函數(shù)要把指針或?qū)Φ刂返囊觅x值給輸入形參。

總之大多時候輸入形參往往是constT&. 若用constT*說明輸入另有處理。所以若您要用constT*, 則應(yīng)有理有據(jù),否則會害得讀者誤解。

6.2. 右值引用

Tip

只在定義移動構(gòu)造函數(shù)與移動賦值操作時使用右值引用. 不要使用std::forward.

定義:

右值引用是一種只能綁定到臨時對象的引用的一種, 其語法與傳統(tǒng)的引用語法相似. 例如,voidf(string&&s); 聲明了一個其參數(shù)是一個字符串的右值引用的函數(shù).

優(yōu)點:

用于定義移動構(gòu)造函數(shù) (使用類的右值引用進行構(gòu)造的函數(shù)) 使得移動一個值而非拷貝之成為可能. 例如, 如果v1是一個vector, 則autov2(std::move(v1))將很可能不再進行大量的數(shù)據(jù)復(fù)制而只是簡單地進行指針操作, 在某些情況下這將帶來大幅度的性能提升.

右值引用使得編寫通用的函數(shù)封裝來轉(zhuǎn)發(fā)其參數(shù)到另外一個函數(shù)成為可能, 無論其參數(shù)是否是臨時對象都能正常工作.

右值引用能實現(xiàn)可移動但不可拷貝的類型, 這一特性對那些在拷貝方面沒有實際需求, 但有時又需要將它們作為函數(shù)參數(shù)傳遞或塞入容器的類型很有用.

要高效率地使用某些標準庫類型, 例如std::unique_ptr,std::move是必需的.

缺點:

右值引用是一個相對比較新的特性 (由 C++11 引入), 它尚未被廣泛理解. 類似引用崩潰, 移動構(gòu)造函數(shù)的自動推導(dǎo)這樣的規(guī)則都是很復(fù)雜的.

結(jié)論:

只在定義移動構(gòu)造函數(shù)與移動賦值操作時使用右值引用, 不要使用std::forward功能函數(shù). 你可能會使用std::move來表示將值從一個對象移動而不是復(fù)制到另一個對象.

6.3. 函數(shù)重載

Tip

若要用好函數(shù)重載,最好能讓讀者一看調(diào)用點(call site)就胸有成竹,不用花心思猜測調(diào)用的重載函數(shù)到底是哪一種。該規(guī)則適用于構(gòu)造函數(shù)。

定義:

你可以編寫一個參數(shù)類型為conststring&的函數(shù), 然后用另一個參數(shù)類型為constchar*的函數(shù)重載它:

class MyClass { public: void Analyze(const string &text); void Analyze(const char *text, size_t textlen);};

優(yōu)點:

通過重載參數(shù)不同的同名函數(shù), 令代碼更加直觀. 模板化代碼需要重載, 同時為使用者帶來便利.

缺點:

如果函數(shù)單單靠不同的參數(shù)類型而重載(acgtyrant 注:這意味著參數(shù)數(shù)量不變),讀者就得十分熟悉 C++ 五花八門的匹配規(guī)則,以了解匹配過程具體到底如何。另外,當派生類只重載了某個函數(shù)的部分變體,繼承語義容易令人困惑。

結(jié)論:

如果您打算重載一個函數(shù), 可以試試改在函數(shù)名里加上參數(shù)信息。例如,用AppendString()和AppendInt()等, 而不是一口氣重載多個Append().

6.4. 缺省參數(shù)

Tip

我們不允許使用缺省函數(shù)參數(shù),少數(shù)極端情況除外。盡可能改用函數(shù)重載。

優(yōu)點:

當您有依賴缺省參數(shù)的函數(shù)時,您也許偶爾會修改修改這些缺省參數(shù)。通過缺省參數(shù),不用再為個別情況而特意定義一大堆函數(shù)了。與函數(shù)重載相比,缺省參數(shù)語法更為清晰,代碼少,也很好地區(qū)分了「必選參數(shù)」和「可選參數(shù)」。

缺點:

缺省參數(shù)會干擾函數(shù)指針,害得后者的函數(shù)簽名(function signature)往往對不上所實際要調(diào)用的函數(shù)簽名。即在一個現(xiàn)有函數(shù)添加缺省參數(shù),就會改變它的類型,那么調(diào)用其地址的代碼可能會出錯,不過函數(shù)重載就沒這問題了。此外,缺省參數(shù)會造成臃腫的代碼,畢竟它們在每一個調(diào)用點(call site)都有重復(fù)(acgtyrant 注:我猜可能是因為調(diào)用函數(shù)的代碼表面上看來省去了不少參數(shù),但編譯器在編譯時還是會在每一個調(diào)用代碼里統(tǒng)統(tǒng)補上所有默認實參信息,造成大量的重復(fù))。函數(shù)重載正好相反,畢竟它們所謂的「缺省參數(shù)」只會出現(xiàn)在函數(shù)定義里。

結(jié)論:

由于缺點并不是很嚴重,有些人依舊偏愛缺省參數(shù)勝于函數(shù)重載。所以除了以下情況,我們要求必須顯式提供所有參數(shù)(acgtyrant 注:即不能再通過缺省參數(shù)來省略參數(shù)了)。

其一,位于.cc文件里的靜態(tài)函數(shù)或匿名空間函數(shù),畢竟都只能在局部文件里調(diào)用該函數(shù)了。

其二,可以在構(gòu)造函數(shù)里用缺省參數(shù),畢竟不可能取得它們的地址。

其三,可以用來模擬變長數(shù)組。

// 通過空 AlphaNum 以支持四個形參string StrCat(const AlphaNum &a, const AlphaNum &b = gEmptyAlphaNum, const AlphaNum &c = gEmptyAlphaNum, const AlphaNum &d = gEmptyAlphaNum);

6.5. 變長數(shù)組和 alloca()

Tip

我們不允許使用變長數(shù)組和alloca().

優(yōu)點:

變長數(shù)組具有渾然天成的語法. 變長數(shù)組和alloca()也都很高效.

缺點:

變長數(shù)組和alloca()不是標準 C++ 的組成部分. 更重要的是, 它們根據(jù)數(shù)據(jù)大小動態(tài)分配堆棧內(nèi)存, 會引起難以發(fā)現(xiàn)的內(nèi)存越界 bugs: “在我的機器上運行的好好的, 發(fā)布后卻莫名其妙的掛掉了”.

結(jié)論:

改用更安全的分配器(allocator),就像std::vector或std::unique_ptr.

6.6. 友元

Tip

我們允許合理的使用友元類及友元函數(shù).

通常友元應(yīng)該定義在同一文件內(nèi), 避免代碼讀者跑到其它文件查找使用該私有成員的類. 經(jīng)常用到友元的一個地方是將FooBuilder聲明為Foo的友元, 以便FooBuilder正確構(gòu)造Foo的內(nèi)部狀態(tài), 而無需將該狀態(tài)暴露出來. 某些情況下, 將一個單元測試類聲明成待測類的友元會很方便.

友元擴大了 (但沒有打破) 類的封裝邊界. 某些情況下, 相對于將類成員聲明為public, 使用友元是更好的選擇, 尤其是如果你只允許另一個類訪問該類的私有成員時. 當然, 大多數(shù)類都只應(yīng)該通過其提供的公有成員進行互操作.

6.7. 異常

Tip

我們不使用 C++ 異常.

優(yōu)點:

異常允許應(yīng)用高層決定如何處理在底層嵌套函數(shù)中「不可能發(fā)生」的失?。╢ailures),不用管那些含糊且容易出錯的錯誤代碼(acgtyrant 注:error code, 我猜是C語言函數(shù)返回的非零 int 值)。

很多現(xiàn)代語言都用異常。引入異常使得 C++ 與 Python, Java 以及其它類 C++ 的語言更一脈相承。

有些第三方 C++ 庫依賴異常,禁用異常就不好用了。

異常是處理構(gòu)造函數(shù)失敗的唯一途徑。雖然可以用工廠函數(shù)(acgtyrant 注:factory function, 出自 C++ 的一種設(shè)計模式,即「簡單工廠模式」)或Init()方法代替異常, 但是前者要求在堆棧分配內(nèi)存,后者會導(dǎo)致剛創(chuàng)建的實例處于 ”無效“ 狀態(tài)。

在測試框架里很好用。

缺點:

在現(xiàn)有函數(shù)中添加throw語句時,您必須檢查所有調(diào)用點。要么讓所有調(diào)用點統(tǒng)統(tǒng)具備最低限度的異常安全保證,要么眼睜睜地看異常一路歡快地往上跑,最終中斷掉整個程序。舉例,f()調(diào)用g(),g()又調(diào)用h(), 且h拋出的異常被f捕獲。當心g, 否則會沒妥善清理好。

還有更常見的,異常會徹底擾亂程序的執(zhí)行流程并難以判斷,函數(shù)也許會在您意料不到的地方返回。您或許會加一大堆何時何處處理異常的規(guī)定來降低風險,然而開發(fā)者的記憶負擔更重了。

異常安全需要RAII和不同的編碼實踐. 要輕松編寫出正確的異常安全代碼需要大量的支持機制. 更進一步地說, 為了避免讀者理解整個調(diào)用表, 異常安全必須隔絕從持續(xù)狀態(tài)寫到 “提交” 狀態(tài)的邏輯. 這一點有利有弊 (因為你也許不得不為了隔離提交而混淆代碼). 如果允許使用異常, 我們就不得不時刻關(guān)注這樣的弊端, 即使有時它們并不值得.

啟用異常會增加二進制文件數(shù)據(jù),延長編譯時間(或許影響?。?,還可能加大地址空間的壓力。

濫用異常會變相鼓勵開發(fā)者去捕捉不合時宜,或本來就已經(jīng)沒法恢復(fù)的「偽異?!?。比如,用戶的輸入不符合格式要求時,也用不著拋異常。如此之類的偽異常列都列不完。

結(jié)論:

從表面上看來,使用異常利大于弊, 尤其是在新項目中. 但是對于現(xiàn)有代碼, 引入異常會牽連到所有相關(guān)代碼. 如果新項目允許異常向外擴散, 在跟以前未使用異常的代碼整合時也將是個麻煩. 因為 Google 現(xiàn)有的大多數(shù) C++ 代碼都沒有異常處理, 引入帶有異常處理的新代碼相當困難.

鑒于 Google 現(xiàn)有代碼不接受異常, 在現(xiàn)有代碼中使用異常比在新項目中使用的代價多少要大一些. 遷移過程比較慢, 也容易出錯. 我們不相信異常的使用有效替代方案, 如錯誤代碼, 斷言等會造成嚴重負擔.

我們并不是基于哲學(xué)或道德層面反對使用異常, 而是在實踐的基礎(chǔ)上. 我們希望在 Google 使用我們自己的開源項目, 但項目中使用異常會為此帶來不便, 因此我們也建議不要在 Google 的開源項目中使用異常. 如果我們需要把這些項目推倒重來顯然不太現(xiàn)實.

對于 Windows 代碼來說, 有個特例.

(YuleFox 注: 對于異常處理, 顯然不是短短幾句話能夠說清楚的, 以構(gòu)造函數(shù)為例, 很多 C++ 書籍上都提到當構(gòu)造失敗時只有異??梢蕴幚? Google 禁止使用異常這一點, 僅僅是為了自身的方便, 說大了, 無非是基于軟件管理成本上, 實際使用中還是自己決定)

6.8. 運行時類型識別

TODO

Tip

我們禁止使用 RTTI.

定義:

RTTI 允許程序員在運行時識別 C++ 類對象的類型. 它通過使用typeid或者dynamic_cast完成.

優(yōu)點:

RTTI 的標準替代 (下面將描述) 需要對有問題的類層級進行修改或重構(gòu). 有時這樣的修改并不是我們所想要的, 甚至是不可取的, 尤其是在一個已經(jīng)廣泛使用的或者成熟的代碼中.

RTTI 在某些單元測試中非常有用. 比如進行工廠類測試時, 用來驗證一個新建對象是否為期望的動態(tài)類型. RTTI 對于管理對象和派生對象的關(guān)系也很有用.

在考慮多個抽象對象時 RTTI 也很好用. 例如:

bool Base::Equal(Base* other) = 0;bool Derived::Equal(Base* other) { Derived* that = dynamic_cast(other); if (that == NULL) return false; ...}

缺點:

在運行時判斷類型通常意味著設(shè)計問題. 如果你需要在運行期間確定一個對象的類型, 這通常說明你需要考慮重新設(shè)計你的類.

隨意地使用 RTTI 會使你的代碼難以維護. 它使得基于類型的判斷樹或者 switch 語句散布在代碼各處. 如果以后要進行修改, 你就必須檢查它們.

結(jié)論:

RTTI 有合理的用途但是容易被濫用, 因此在使用時請務(wù)必注意. 在單元測試中可以使用 RTTI, 但是在其他代碼中請盡量避免. 尤其是在新代碼中, 使用 RTTI 前務(wù)必三思. 如果你的代碼需要根據(jù)不同的對象類型執(zhí)行不同的行為的話, 請考慮用以下的兩種替代方案之一查詢類型:

虛函數(shù)可以根據(jù)子類類型的不同而執(zhí)行不同代碼. 這是把工作交給了對象本身去處理.

如果這一工作需要在對象之外完成, 可以考慮使用雙重分發(fā)的方案, 例如使用訪問者設(shè)計模式. 這就能夠在對象之外進行類型判斷.

如果程序能夠保證給定的基類實例實際上都是某個派生類的實例, 那么就可以自由使用 dynamic_cast. 在這種情況下, 使用 dynamic_cast 也是一種替代方案.

基于類型的判斷樹是一個很強的暗示, 它說明你的代碼已經(jīng)偏離正軌了. 不要像下面這樣:

if (typeid(*data) == typeid(D1)) { ...} else if (typeid(*data) == typeid(D2)) { ...} else if (typeid(*data) == typeid(D3)) {...

一旦在類層級中加入新的子類, 像這樣的代碼往往會崩潰. 而且, 一旦某個子類的屬性改變了, 你很難找到并修改所有受影響的代碼塊.

不要去手工實現(xiàn)一個類似 RTTI 的方案. 反對 RTTI 的理由同樣適用于這些方案, 比如帶類型標簽的類繼承體系. 而且, 這些方案會掩蓋你的真實意圖.

6.9. 類型轉(zhuǎn)換

Tip

使用 C++ 的類型轉(zhuǎn)換, 如static_cast<>(). 不要使用inty=(int)x或inty=int(x)等轉(zhuǎn)換方式;

定義:

C++ 采用了有別于 C 的類型轉(zhuǎn)換機制, 對轉(zhuǎn)換操作進行歸類.

優(yōu)點:

C 語言的類型轉(zhuǎn)換問題在于模棱兩可的操作; 有時是在做強制轉(zhuǎn)換 (如(int)3.5), 有時是在做類型轉(zhuǎn)換 (如(int)"hello"). 另外, C++ 的類型轉(zhuǎn)換在查找時更醒目.

缺點:

惡心的語法.

結(jié)論:

不要使用 C 風格類型轉(zhuǎn)換. 而應(yīng)該使用 C++ 風格.

用static_cast替代 C 風格的值轉(zhuǎn)換, 或某個類指針需要明確的向上轉(zhuǎn)換為父類指針時.

用const_cast去掉const限定符.

用reinterpret_cast指針類型和整型或其它指針之間進行不安全的相互轉(zhuǎn)換. 僅在你對所做一切了然于心時使用.

至于dynamic_cast參見6.8. 運行時類型識別.

6.10. 流

Tip

只在記錄日志時使用流.

定義:

流用來替代printf()和scanf().

優(yōu)點:

有了流, 在打印時不需要關(guān)心對象的類型. 不用擔心格式化字符串與參數(shù)列表不匹配 (雖然在 gcc 中使用printf也不存在這個問題). 流的構(gòu)造和析構(gòu)函數(shù)會自動打開和關(guān)閉對應(yīng)的文件.

缺點:

流使得pread()等功能函數(shù)很難執(zhí)行. 如果不使用printf風格的格式化字符串, 某些格式化操作 (尤其是常用的格式字符串%.*s) 用流處理性能是很低的. 流不支持字符串操作符重新排序 (%1s), 而這一點對于軟件國際化很有用.

結(jié)論:

不要使用流, 除非是日志接口需要. 使用printf之類的代替.

使用流還有很多利弊, 但代碼一致性勝過一切. 不要在代碼中使用流.

拓展討論:

對這一條規(guī)則存在一些爭論, 這兒給出點深層次原因. 回想一下唯一性原則 (Only One Way): 我們希望在任何時候都只使用一種確定的 I/O 類型, 使代碼在所有 I/O 處都保持一致. 因此, 我們不希望用戶來決定是使用流還是printf+read/write. 相反, 我們應(yīng)該決定到底用哪一種方式. 把日志作為特例是因為日志是一個非常獨特的應(yīng)用, 還有一些是歷史原因.

流的支持者們主張流是不二之選, 但觀點并不是那么清晰有力. 他們指出的流的每個優(yōu)勢也都是其劣勢. 流最大的優(yōu)勢是在輸出時不需要關(guān)心打印對象的類型. 這是一個亮點. 同時, 也是一個不足: 你很容易用錯類型, 而編譯器不會報警. 使用流時容易造成的這類錯誤:

cout << this; // 輸出地址cout << *this; // 輸出值

由于<

有人說printf的格式化丑陋不堪, 易讀性差, 但流也好不到哪兒去. 看看下面兩段代碼吧, 實現(xiàn)相同的功能, 哪個更清晰?

cerr << "Error connecting to '" << foo->bar()->hostname.first << ":" << foo->bar()->hostname.second << ": " << strerror(errno);fprintf(stderr, "Error connecting to '%s:%u: %s", foo->bar()->hostname.first, foo->bar()->hostname.second, strerror(errno));

你可能會說, “把流封裝一下就會比較好了”, 這兒可以, 其他地方呢? 而且不要忘了, 我們的目標是使語言更緊湊, 而不是添加一些別人需要學(xué)習的新裝備.

每一種方式都是各有利弊, “沒有最好, 只有更適合”. 簡單性原則告誡我們必須從中選擇其一, 最后大多數(shù)決定采用printf+read/write.

6.11. 前置自增和自減

Tip

對于迭代器和其他模板對象使用前綴形式 (++i) 的自增, 自減運算符.

定義:

對于變量在自增 (++i或i++) 或自減 (--i或i--) 后表達式的值又沒有沒用到的情況下, 需要確定到底是使用前置還是后置的自增 (自減).

優(yōu)點:

不考慮返回值的話, 前置自增 (++i) 通常要比后置自增 (i++) 效率更高. 因為后置自增 (或自減) 需要對表達式的值i進行一次拷貝. 如果i是迭代器或其他非數(shù)值類型, 拷貝的代價是比較大的. 既然兩種自增方式實現(xiàn)的功能一樣, 為什么不總是使用前置自增呢?

缺點:

在 C 開發(fā)中, 當表達式的值未被使用時, 傳統(tǒng)的做法是使用后置自增, 特別是在for循環(huán)中. 有些人覺得后置自增更加易懂, 因為這很像自然語言, 主語 (i) 在謂語動詞 (++) 前.

結(jié)論:

對簡單數(shù)值 (非對象), 兩種都無所謂. 對迭代器和模板類型, 使用前置自增 (自減).

6.12.const用法

Tip

我們強烈建議你在任何可能的情況下都要使用const. 此外有時改用 C++11 推出的 constexpr 更好。

定義:

在聲明的變量或參數(shù)前加上關(guān)鍵字const用于指明變量值不可被篡改 (如constintfoo). 為類中的函數(shù)加上const限定符表明該函數(shù)不會修改類成員變量的狀態(tài) (如classFoo{intBar(charc)const;};).

優(yōu)點:

大家更容易理解如何使用變量. 編譯器可以更好地進行類型檢測, 相應(yīng)地, 也能生成更好的代碼. 人們對編寫正確的代碼更加自信, 因為他們知道所調(diào)用的函數(shù)被限定了能或不能修改變量值. 即使是在無鎖的多線程編程中, 人們也知道什么樣的函數(shù)是安全的.

缺點:

const是入侵性的: 如果你向一個函數(shù)傳入const變量, 函數(shù)原型聲明中也必須對應(yīng)const參數(shù) (否則變量需要const_cast類型轉(zhuǎn)換), 在調(diào)用庫函數(shù)時顯得尤其麻煩.

結(jié)論:

const變量, 數(shù)據(jù)成員, 函數(shù)和參數(shù)為編譯時類型檢測增加了一層保障; 便于盡早發(fā)現(xiàn)錯誤. 因此, 我們強烈建議在任何可能的情況下使用const:

如果函數(shù)不會修改傳你入的引用或指針類型參數(shù), 該參數(shù)應(yīng)聲明為const.

盡可能將函數(shù)聲明為const. 訪問函數(shù)應(yīng)該總是const. 其他不會修改任何數(shù)據(jù)成員, 未調(diào)用非const函數(shù), 不會返回數(shù)據(jù)成員非const指針或引用的函數(shù)也應(yīng)該聲明成const.

如果數(shù)據(jù)成員在對象構(gòu)造之后不再發(fā)生變化, 可將其定義為const.

然而, 也不要發(fā)了瘋似的使用const. 像constint*const*constx;就有些過了, 雖然它非常精確的描述了常量x. 關(guān)注真正有幫助意義的信息: 前面的例子寫成constint**x就夠了.

關(guān)鍵字mutable可以使用, 但是在多線程中是不安全的, 使用時首先要考慮線程安全.

const的位置:

有人喜歡intconst*foo形式, 不喜歡constint*foo, 他們認為前者更一致因此可讀性也更好: 遵循了const總位于其描述的對象之后的原則. 但是一致性原則不適用于此, “不要過度使用” 的聲明可以取消大部分你原本想保持的一致性. 將const放在前面才更易讀, 因為在自然語言中形容詞 (const) 是在名詞 (int) 之前.

這是說, 我們提倡但不強制const在前. 但要保持代碼的一致性! (Yang.Y 注: 也就是不要在一些地方把const寫在類型前面, 在其他地方又寫在后面, 確定一種寫法, 然后保持一致.)

6.13.constexpr用法

Tip

在 C++11 里,用 constexpr 來定義真正的常量,或?qū)崿F(xiàn)常量初始化。

定義:

變量可以被聲明成 constexpr 以表示它是真正意義上的常量,即在編譯時和運行時都不變。函數(shù)或構(gòu)造函數(shù)也可以被聲明成 constexpr, 以用來定義 constexpr 變量。

優(yōu)點:

如今 constexpr 就可以定義浮點式的真?常量,不用再依賴字面值了;也可以定義用戶自定義類型上的常量;甚至也可以定義函數(shù)調(diào)用所返回的常量。

缺點:

若過早把變量優(yōu)化成 constexpr 變量,將來又要把它改為常規(guī)變量時,挺麻煩的;當前對constexpr函數(shù)和構(gòu)造函數(shù)中允許的限制可能會導(dǎo)致這些定義中解決的方法模糊。

結(jié)論:

靠 constexpr 特性,方才實現(xiàn)了 C++ 在接口上打造真正常量機制的可能。好好用 constexpr 來定義真?常量以及支持常量的函數(shù)。避免復(fù)雜的函數(shù)定義,以使其能夠與constexpr一起使用。 千萬別癡心妄想地想靠 constexpr 來強制代碼「內(nèi)聯(lián)」。

6.14. 整型

Tip

C++ 內(nèi)建整型中, 僅使用int. 如果程序中需要不同大小的變量, 可以使用中長度精確的整型, 如int16_t.如果您的變量可能不小于 2^31 (2GiB), 就用 64 位變量比如int64_t. 此外要留意,哪怕您的值并不會超出 int 所能夠表示的范圍,在計算過程中也可能會溢出。所以拿不準時,干脆用更大的類型。

定義:

C++ 沒有指定整型的大小. 通常人們假定short是 16 位,int是 32 位,long是 32 位,longlong是 64 位.

優(yōu)點:

保持聲明統(tǒng)一.

缺點:

C++ 中整型大小因編譯器和體系結(jié)構(gòu)的不同而不同.

結(jié)論:

定義了int16_t,uint32_t,int64_t等整型, 在需要確保整型大小時可以使用它們代替short,unsignedlonglong等. 在 C 整型中, 只使用int. 在合適的情況下, 推薦使用標準類型如size_t和ptrdiff_t.

如果已知整數(shù)不會太大, 我們常常會使用int, 如循環(huán)計數(shù). 在類似的情況下使用原生類型int. 你可以認為int至少為 32 位, 但不要認為它會多于32位. 如果需要 64 位整型, 用int64_t或uint64_t.

對于大整數(shù), 使用int64_t.

不要使用uint32_t等無符號整型, 除非你是在表示一個位組而不是一個數(shù)值, 或是你需要定義二進制補碼溢出. 尤其是不要為了指出數(shù)值永不會為負, 而使用無符號類型. 相反, 你應(yīng)該使用斷言來保護數(shù)據(jù).

如果您的代碼涉及容器返回的大?。╯ize),確保其類型足以應(yīng)付容器各種可能的用法。拿不準時,類型越大越好。

小心整型類型轉(zhuǎn)換和整型提升(acgtyrant 注:integer promotions, 比如int與unsignedint運算時,前者被提升為unsignedint而有可能溢出),總有意想不到的后果。

關(guān)于無符號整數(shù):

有些人, 包括一些教科書作者, 推薦使用無符號類型表示非負數(shù). 這種做法試圖達到自我文檔化. 但是, 在 C 語言中, 這一優(yōu)點被由其導(dǎo)致的 bug 所淹沒. 看看下面的例子:

for (unsigned int i = foo.Length()-1; i >= 0; --i) ...

上述循環(huán)永遠不會退出! 有時 gcc 會發(fā)現(xiàn)該 bug 并報警, 但大部分情況下都不會. 類似的 bug 還會出現(xiàn)在比較有符合變量和無符號變量時. 主要是 C 的類型提升機制會致使無符號類型的行為出乎你的意料.

因此, 使用斷言來指出變量為非負數(shù), 而不是使用無符號型!

6.15. 64 位下的可移植性

Tip

代碼應(yīng)該對 64 位和 32 位系統(tǒng)友好. 處理打印, 比較, 結(jié)構(gòu)體對齊時應(yīng)切記:

對于某些類型,printf()的指示符在 32 位和 64 位系統(tǒng)上可移植性不是很好. C99 標準定義了一些可移植的格式化指示符. 不幸的是, MSVC 7.1 并非全部支持, 而且標準中也有所遺漏, 所以有時我們不得不自己定義一個丑陋的版本 (頭文件inttypes.h仿標準風格):

// printf macros for size_t, in the style of inttypes.h#ifdef _LP64#define __PRIS_PREFIX "z"#else#define __PRIS_PREFIX#endif// Use these macros after a % in a printf format string// to get correct 32/64 bit behavior, like this:// size_t size = records.size();// printf("%"PRIuS"\n", size);#define PRIdS __PRIS_PREFIX "d"#define PRIxS __PRIS_PREFIX "x"#define PRIuS __PRIS_PREFIX "u"#define PRIXS __PRIS_PREFIX "X"#define PRIoS __PRIS_PREFIX "o"

類型 不要使用 使用 備注
void*(或其他指針類型) %lx %p
int64_t %qd,%lld %"PRId64"
uint64_t %qu,%llu,%llx %"PRIu64",%"PRIx64"
size_t %u %"PRIuS",%"PRIxS" C99 規(guī)定%zu
ptrdiff_t %d %"PRIdS" C99 規(guī)定%zd

注意PRI*宏會被編譯器擴展為獨立字符串. 因此如果使用非常量的格式化字符串, 需要將宏的值而不是宏名插入格式中. 使用PRI*宏同樣可以在%后包含長度指示符. 例如,printf("x=%30"PRIuS"\n",x)在 32 位 Linux 上將被展開為printf("x=%30""u""\n",x), 編譯器當成printf("x=%30u\n",x)處理 (Yang.Y 注: 這在 MSVC 6.0 上行不通, VC 6 編譯器不會自動把引號間隔的多個字符串連接一個長字符串).

記住sizeof(void*)!=sizeof(int). 如果需要一個指針大小的整數(shù)要用intptr_t.

你要非常小心的對待結(jié)構(gòu)體對齊, 尤其是要持久化到磁盤上的結(jié)構(gòu)體 (Yang.Y 注: 持久化 - 將數(shù)據(jù)按字節(jié)流順序保存在磁盤文件或數(shù)據(jù)庫中). 在 64 位系統(tǒng)中, 任何含有int64_t/uint64_t成員的類/結(jié)構(gòu)體, 缺省都以 8 字節(jié)在結(jié)尾對齊. 如果 32 位和 64 位代碼要共用持久化的結(jié)構(gòu)體, 需要確保兩種體系結(jié)構(gòu)下的結(jié)構(gòu)體對齊一致. 大多數(shù)編譯器都允許調(diào)整結(jié)構(gòu)體對齊. gcc 中可使用__attribute__((packed)). MSVC 則提供了#pragmapack()和__declspec(align())(YuleFox 注, 解決方案的項目屬性里也可以直接設(shè)置).

創(chuàng)建 64 位常量時使用 LL 或 ULL 作為后綴, 如:

int64_t my_value = 0x123456789LL;uint64_t my_mask = 3ULL << 48;

如果你確實需要 32 位和 64 位系統(tǒng)具有不同代碼, 可以使用#ifdef_LP64指令來切分 32/64 位代碼. (盡量不要這么做, 如果非用不可, 盡量使修改局部化)

6.16. 預(yù)處理宏

Tip

使用宏時要非常謹慎, 盡量以內(nèi)聯(lián)函數(shù), 枚舉和常量代替之.

宏意味著你和編譯器看到的代碼是不同的. 這可能會導(dǎo)致異常行為, 尤其因為宏具有全局作用域.

值得慶幸的是, C++ 中, 宏不像在 C 中那么必不可少. 以往用宏展開性能關(guān)鍵的代碼, 現(xiàn)在可以用內(nèi)聯(lián)函數(shù)替代. 用宏表示常量可被const變量代替. 用宏 “縮寫” 長變量名可被引用代替. 用宏進行條件編譯… 這個, 千萬別這么做, 會令測試更加痛苦 (#define防止頭文件重包含當然是個特例).

宏可以做一些其他技術(shù)無法實現(xiàn)的事情, 在一些代碼庫 (尤其是底層庫中) 可以看到宏的某些特性 (如用#字符串化, 用##連接等等). 但在使用前, 仔細考慮一下能不能不使用宏達到同樣的目的.

下面給出的用法模式可以避免使用宏帶來的問題; 如果你要宏, 盡可能遵守:

不要在.h文件中定義宏.

在馬上要使用時才進行#define, 使用后要立即#undef.

不要只是對已經(jīng)存在的宏使用#undef,選擇一個不會沖突的名稱;

不要試圖使用展開后會導(dǎo)致 C++ 構(gòu)造不穩(wěn)定的宏, 不然也至少要附上文檔說明其行為.

不要用##處理函數(shù),類和變量的名字。

6.17. 0,nullptr和NULL

Tip

整數(shù)用0, 實數(shù)用0.0, 指針用nullptr或NULL, 字符 (串) 用'\0'.

整數(shù)用0, 實數(shù)用0.0, 這一點是毫無爭議的.

對于指針 (地址值), 到底是用0,NULL還是nullptr. C++11 項目用nullptr; C++03 項目則用NULL, 畢竟它看起來像指針。實際上,一些 C++ 編譯器對NULL的定義比較特殊,可以輸出有用的警告,特別是sizeof(NULL)就和sizeof(0)不一樣。

字符 (串) 用'\0', 不僅類型正確而且可讀性好.

6.18. sizeof

Tip

盡可能用sizeof(varname)代替sizeof(type).

使用sizeof(varname)是因為當代碼中變量類型改變時會自動更新. 您或許會用sizeof(type)處理不涉及任何變量的代碼,比如處理來自外部或內(nèi)部的數(shù)據(jù)格式,這時用變量就不合適了。

Struct data;Struct data; memset(&data, 0, sizeof(data));

Warning

memset(&data, 0, sizeof(Struct));if (raw_size < sizeof(int)) { LOG(ERROR) << "compressed record not big enough for count: " << raw_size; return false;}

6.19. auto

Tip

用auto繞過煩瑣的類型名,只要可讀性好就繼續(xù)用,別用在局部變量之外的地方。

定義:

C++11 中,若變量被聲明成auto, 那它的類型就會被自動匹配成初始化表達式的類型。您可以用auto來復(fù)制初始化或綁定引用。

vector v;...auto s1 = v[0]; // 創(chuàng)建一份 v[0] 的拷貝。const auto& s2 = v[0]; // s2 是 v[0] 的一個引用。

優(yōu)點:

C++ 類型名有時又長又臭,特別是涉及模板或命名空間的時候。就像:

sparse_hash_map::iterator iter = m.find(val);

返回類型好難讀,代碼目的也不夠一目了然。重構(gòu)其:

auto iter = m.find(val);

好多了。

沒有auto的話,我們不得不在同一個表達式里寫同一個類型名兩次,無謂的重復(fù),就像:

diagnostics::ErrorStatus* status = new diagnostics::ErrorStatus("xyz");

有了 auto, 可以更方便地用中間變量,顯式編寫它們的類型輕松點。

缺點:

類型夠明顯時,特別是初始化變量時,代碼才會夠一目了然。但以下就不一樣了:

auto i = x.Lookup(key);

看不出其類型是啥,x 的類型聲明恐怕遠在幾百行之外了。

程序員必須會區(qū)分auto和constauto&的不同之處,否則會復(fù)制錯東西。

auto 和 C++11 列表初始化的合體令人摸不著頭腦:

auto x(3); // 圓括號。auto y{3}; // 大括號。

它們不是同一回事——x是int,y則是std::initializer_list. 其它一般不可見的代理類型(acgtyrant 注:normally-invisible proxy types, 它涉及到 C++ 鮮為人知的坑:Why is vector not a STL container?)也有大同小異的陷阱。

如果在接口里用auto, 比如聲明頭文件里的一個常量,那么只要僅僅因為程序員一時修改其值而導(dǎo)致類型變化的話——API 要翻天覆地了。

結(jié)論:

auto只能用在局部變量里用。別用在文件作用域變量,命名空間作用域變量和類數(shù)據(jù)成員里。永遠別列表初始化auto變量。

auto還可以和 C++11 特性「尾置返回類型(trailing return type)」一起用,不過后者只能用在 lambda 表達式里。

6.20. 列表初始化

Tip

你可以用列表初始化。

早在 C++03 里,聚合類型(aggregate types)就已經(jīng)可以被列表初始化了,比如數(shù)組和不自帶構(gòu)造函數(shù)的結(jié)構(gòu)體:

struct Point { int x; int y; };Point p = {1, 2};

C++11 中,該特性得到進一步的推廣,任何對象類型都可以被列表初始化。示范如下:

// Vector 接收了一個初始化列表。vector v{"foo", "bar"};// 不考慮細節(jié)上的微妙差別,大致上相同。// 您可以任選其一。vector v = {"foo", "bar"};// 可以配合 new 一起用。auto p = new vector{"foo", "bar"};// map 接收了一些 pair, 列表初始化大顯神威。map m = {{1, "one"}, {2, "2"}};// 初始化列表也可以用在返回類型上的隱式轉(zhuǎn)換。vector test_function() { return {1, 2, 3}; }// 初始化列表可迭代。for (int i : {-1, -2, -3}) {}// 在函數(shù)調(diào)用里用列表初始化。void TestFunction2(vector v) {}TestFunction2({1, 2, 3});

用戶自定義類型也可以定義接收std::initializer_list的構(gòu)造函數(shù)和賦值運算符,以自動列表初始化:

class MyType { public: // std::initializer_list 專門接收 init 列表。 // 得以值傳遞。 MyType(std::initializer_list init_list) { for (int i : init_list) append(i); } MyType& operator=(std::initializer_list init_list) { clear(); for (int i : init_list) append(i); }};MyType m{2, 3, 5, 7};

最后,列表初始化也適用于常規(guī)數(shù)據(jù)類型的構(gòu)造,哪怕沒有接收std::initializer_list的構(gòu)造函數(shù)。

double d{1.23};// MyOtherType 沒有 std::initializer_list 構(gòu)造函數(shù), // 直接上接收常規(guī)類型的構(gòu)造函數(shù)。class MyOtherType { public: explicit MyOtherType(string); MyOtherType(int, string);};MyOtherType m = {1, "b"};// 不過如果構(gòu)造函數(shù)是顯式的(explict),您就不能用 `= {}` 了。MyOtherType m{"b"};

千萬別直接列表初始化 auto 變量,看下一句,估計沒人看得懂:

Warning

auto d = {1.23}; // d 即是 std::initializer_listauto d = double{1.23}; // 善哉 -- d 即為 double, 并非 std::initializer_list.

至于格式化,參見9.7. 列表初始化格式.

6.21. Lambda 表達式

Tip

適當使用 lambda 表達式。別用默認 lambda 捕獲,所有捕獲都要顯式寫出來。

定義:

Lambda 表達式是創(chuàng)建匿名函數(shù)對象的一種簡易途徑,常用于把函數(shù)當參數(shù)傳,例如:

std::sort(v.begin(), v.end(), [](int x, int y) { return Weight(x) < Weight(y);});

C++11 首次提出 Lambdas, 還提供了一系列處理函數(shù)對象的工具,比如多態(tài)包裝器(polymorphic wrapper)std::function.

優(yōu)點:

傳函數(shù)對象給 STL 算法,Lambdas 最簡易,可讀性也好。

Lambdas,std::functions和std::bind可以搭配成通用回調(diào)機制(general purpose callback mechanism);寫接收有界函數(shù)為參數(shù)的函數(shù)也很容易了。

缺點:

Lambdas 的變量捕獲略旁門左道,可能會造成懸空指針。

Lambdas 可能會失控;層層嵌套的匿名函數(shù)難以閱讀。

結(jié)論:

按 format 小用 lambda 表達式怡情。

禁用默認捕獲,捕獲都要顯式寫出來。打比方,比起[=](intx){returnx+n;}, 您該寫成[n](intx){returnx+n;}才對,這樣讀者也好一眼看出n是被捕獲的值。

匿名函數(shù)始終要簡短,如果函數(shù)體超過了五行,那么還不如起名(acgtyrant 注:即把 lambda 表達式賦值給對象),或改用函數(shù)。

如果可讀性更好,就顯式寫出 lambd 的尾置返回類型,就像auto.

6.22. 模板編程

Tip

不要使用復(fù)雜的模板編程

定義:

模板編程指的是利用c++ 模板實例化機制是圖靈完備性, 可以被用來實現(xiàn)編譯時刻的類型判斷的一系列編程技巧

優(yōu)點:

模板編程能夠?qū)崿F(xiàn)非常靈活的類型安全的接口和極好的性能, 一些常見的工具比如Google Test, std::tuple, std::function 和 Boost.Spirit. 這些工具如果沒有模板是實現(xiàn)不了的

缺點:

模板編程所使用的技巧對于使用c++不是很熟練的人是比較晦澀, 難懂的. 在復(fù)雜的地方使用模板的代碼讓人更不容易讀懂, 并且debug 和 維護起來都很麻煩

模板編程經(jīng)常會導(dǎo)致編譯出錯的信息非常不友好: 在代碼出錯的時候, 即使這個接口非常的簡單, 模板內(nèi)部復(fù)雜的實現(xiàn)細節(jié)也會在出錯信息顯示. 導(dǎo)致這個編譯出錯信息看起來非常難以理解.

大量的使用模板編程接口會讓重構(gòu)工具(Visual Assist X, Refactor for C++等等)更難發(fā)揮用途. 首先模板的代碼會在很多上下文里面擴展開來, 所以很難確認重構(gòu)對所有的這些展開的代碼有用, 其次有些重構(gòu)工具只對已經(jīng)做過模板類型替換的代碼的AST 有用. 因此重構(gòu)工具對這些模板實現(xiàn)的原始代碼并不有效, 很難找出哪些需要重構(gòu).

結(jié)論:

模板編程有時候能夠?qū)崿F(xiàn)更簡潔更易用的接口, 但是更多的時候卻適得其反. 因此模板編程最好只用在少量的基礎(chǔ)組件, 基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)上, 因為模板帶來的額外的維護成本會被大量的使用給分擔掉

在使用模板編程或者其他復(fù)雜的模板技巧的時候, 你一定要再三考慮一下. 考慮一下你們團隊成員的平均水平是否能夠讀懂并且能夠維護你寫的模板代碼.或者一個非c++ 程序員和一些只是在出錯的時候偶爾看一下代碼的人能夠讀懂這些錯誤信息或者能夠跟蹤函數(shù)的調(diào)用流程. 如果你使用遞歸的模板實例化, 或者類型列表, 或者元函數(shù), 又或者表達式模板, 或者依賴SFINAE, 或者sizeof 的trick 手段來檢查函數(shù)是否重載, 那么這說明你模板用的太多了, 這些模板太復(fù)雜了, 我們不推薦使用

如果你使用模板編程, 你必須考慮盡可能的把復(fù)雜度最小化, 并且盡量不要讓模板對外暴漏. 你最好只在實現(xiàn)里面使用模板, 然后給用戶暴露的接口里面并不使用模板, 這樣能提高你的接口的可讀性. 并且你應(yīng)該在這些使用模板的代碼上寫盡可能詳細的注釋. 你的注釋里面應(yīng)該詳細的包含這些代碼是怎么用的, 這些模板生成出來的代碼大概是什么樣子的. 還需要額外注意在用戶錯誤使用你的模板代碼的時候需要輸出更人性化的出錯信息. 因為這些出錯信息也是你的接口的一部分, 所以你的代碼必須調(diào)整到這些錯誤信息在用戶看起來應(yīng)該是非常容易理解, 并且用戶很容易知道如何修改這些錯誤

6.23. Boost 庫

Tip

只使用 Boost 中被認可的庫.

定義:

Boost 庫集是一個廣受歡迎, 經(jīng)過同行鑒定, 免費開源的 C++ 庫集.

優(yōu)點:

Boost代碼質(zhì)量普遍較高, 可移植性好, 填補了 C++ 標準庫很多空白, 如型別的特性, 更完善的綁定器, 更好的智能指針。

缺點:

某些 Boost 庫提倡的編程實踐可讀性差, 比如元編程和其他高級模板技術(shù), 以及過度 “函數(shù)化” 的編程風格.

結(jié)論:

為了向閱讀和維護代碼的人員提供更好的可讀性, 我們只允許使用 Boost 一部分經(jīng)認可的特性子集. 目前允許使用以下庫:

Call Traits:boost/call_traits.hpp

Compressed Pair:boost/compressed_pair.hpp

Property Map:boost/property_map.hpp

The part ofIteratorthat deals with defining iterators:boost/iterator/iterator_adaptor.hpp,boost/iterator/iterator_facade.hpp, andboost/function_output_iterator.hpp

The part ofPolygonthat deals with Voronoi diagram construction and doesn’t depend on the rest of Polygon:boost/polygon/voronoi_builder.hpp,boost/polygon/voronoi_diagram.hpp, andboost/polygon/voronoi_geometry_type.hpp

Bimap:boost/bimap

Statistical Distributions and Functions:boost/math/distributions

Multi-index:boost/multi_index

Heap:boost/heap

The flat containers fromContainer:boost/container/flat_map, andboost/container/flat_set

我們正在積極考慮增加其它 Boost 特性, 所以列表中的規(guī)則將不斷變化.

以下庫可以用,但由于如今已經(jīng)被 C++ 11 標準庫取代,不再鼓勵:

Pointer Container:boost/ptr_container, 改用std::unique_ptr

Array:boost/array.hpp, 改用std::array

6.24. C++11

Tip

適當用 C++11(前身是 C++0x)的庫和語言擴展,在貴項目用 C++11 特性前三思可移植性。

定義:

C++11 有眾多語言和庫上的`變革 `_ 。

優(yōu)點:

在二〇一四年八月之前,C++11 一度是官方標準,被大多 C++ 編譯器支持。它標準化很多我們早先就在用的 C++ 擴展,簡化了不少操作,大大改善了性能和安全。

缺點:

C++11 相對于前身,復(fù)雜極了:1300 頁 vs 800 頁!很多開發(fā)者也不怎么熟悉它。于是從長遠來看,前者特性對代碼可讀性以及維護代價難以預(yù)估。我們說不準什么時候采納其特性,特別是在被迫依賴老實工具的項目上。

和6.23. Boost 庫一樣,有些 C++11 擴展提倡實則對可讀性有害的編程實踐——就像去除冗余檢查(比如類型名)以幫助讀者,或是鼓勵模板元編程等等。有些擴展在功能上與原有機制沖突,容易招致困惑以及遷移代價。

缺點:

C++11 特性除了個別情況下,可以用一用。除了本指南會有不少章節(jié)會加以討若干 C++11 特性之外,以下特性最好不要用:

尾置返回類型,比如用autofoo()->int代替intfoo(). 為了兼容于現(xiàn)有代碼的聲明風格。

編譯時合數(shù), 因為它涉及一個重模板的接口風格。

頭文件,因為編譯器尚不支持。

默認 lambda 捕獲。

譯者(acgtyrant)筆記

實際上,缺省參數(shù)會改變函數(shù)簽名的前提是改變了它接收的參數(shù)數(shù)量,比如把voida()改成voida(intb=0), 開發(fā)者改變其代碼的初衷也許是,在不改變「代碼兼容性」的同時,又提供了可選 int 參數(shù)的余地,然而這終究會破壞函數(shù)指針上的兼容性,畢竟函數(shù)簽名確實變了。

此外把自帶缺省參數(shù)的函數(shù)地址賦值給指針時,會丟失缺省參數(shù)信息。

我還發(fā)現(xiàn)濫用缺省參數(shù)會害得讀者光只看調(diào)用代碼的話,會誤以為其函數(shù)接受的參數(shù)數(shù)量比實際上還要少。

friend實際上只對函數(shù)/類賦予了對其所在類的訪問權(quán)限,并不是有效的聲明語句。所以除了在頭文件類內(nèi)部寫 friend 函數(shù)/類,還要在類作用域之外正式地聲明一遍,最后在對應(yīng)的.cc文件加以定義。

本風格指南都強調(diào)了「友元應(yīng)該定義在同一文件內(nèi),避免代碼讀者跑到其它文件查找使用該私有成員的類」。那么可以把其聲明放在類聲明所在的頭文件,定義也放在類定義所在的文件。

由于友元函數(shù)/類并不是類的一部分,自然也不會是類可調(diào)用的公有接口,于是我主張全集中放在類的尾部,即的數(shù)據(jù)成員之后,參考聲明順序。

對使用 C++ 異常處理應(yīng)具有怎樣的態(tài)度?非常值得一讀。

注意初始化 const 對象時,必須在初始化的同時值初始化。

用斷言代替無符號整型類型,深有啟發(fā)。

auto 在涉及迭代器的循環(huán)語句里挺常用。

Should the trailing return type syntax style become the default for new C++11 programs?討論了 auto 與尾置返回類型一起用的全新編碼風格,值得一看。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • Google
    +關(guān)注

    關(guān)注

    5

    文章

    1752

    瀏覽量

    57327
  • 編程
    +關(guān)注

    關(guān)注

    88

    文章

    3544

    瀏覽量

    93469
  • C++
    C++
    +關(guān)注

    關(guān)注

    21

    文章

    2090

    瀏覽量

    73404

原文標題:Google C++ 編程規(guī)范 - 4

文章出處:【微信號:C_Expert,微信公眾號:C語言專家集中營】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    JAVA編程實例:多種風格的窗口

    JAVA編程實例:多種風格的窗口 
    發(fā)表于 12-06 12:37

    MATLAB 編程風格指南

    thebeginning.”(良好的寫作規(guī)范的程序比糟糕的寫作規(guī)范的要好,因為他們具有較少的錯誤、易于調(diào)試與修改,因此,從一開始就考慮風格是很重要的)。本指南列舉的MATLAB 代碼編寫的建議在
    發(fā)表于 09-22 16:19

    Google C++編程指南

    Google C++編程指南目標:增強代碼一致性,創(chuàng)建通用的、必需的習慣用語和模式可以使代碼更加容易理解C++是一門包含大量高級特性的巨型語言,某些情況下,我們會限制甚至禁止使用某些特性使代碼簡化
    發(fā)表于 11-29 09:15

    MATLAB編程風格指南

    有關(guān) MATLAB代碼的建議通常強調(diào)的是效率,譬如說有關(guān)“不要用循環(huán)”等的建議,本指南與之不同。本指南主要考慮的是代碼(格式)的正確性、清晰性與通用性。本指南的目的在
    發(fā)表于 07-18 10:54 ?0次下載

    linux內(nèi)核C語言的編程風格

    linux 內(nèi)核C語言的編程風格
    發(fā)表于 09-26 14:22 ?0次下載

    Google編程風格指南(一)

    使代碼易于管理的方法之一是加強代碼一致性. 讓任何程序員都可以快速讀懂你的代碼這點非常重要. 保持統(tǒng)一編程風格并遵守約定意味著可以很容易根據(jù) “模式匹配” 規(guī)則來推斷各種標識符的含義. 創(chuàng)建通用
    的頭像 發(fā)表于 09-27 17:57 ?3059次閱讀

    Google編程風格指南(二)

    鼓勵在 .cc 文件內(nèi)使用匿名命名空間或 static 聲明. 使用具名的命名空間時, 其名稱可基于項目名或相對路徑. 禁止使用 using 指示(using-directive)。禁止使用內(nèi)聯(lián)命名空間(inline namespace)。
    的頭像 發(fā)表于 09-27 18:01 ?2551次閱讀

    Google編程風格指南(三)

    C/C++ 中的函數(shù)參數(shù)或者是函數(shù)的輸入, 或者是函數(shù)的輸出, 或兼而有之. 輸入?yún)?shù)通常是值參或 const 引用, 輸出參數(shù)或輸入/輸出參數(shù)則一般為非 const 指針. 在排列參數(shù)順序時, 將所有的輸入?yún)?shù)置于輸出參數(shù)之前. 特別要注意, 在加入新參數(shù)時不要因為它們是新參數(shù)就置于參數(shù)列表最后, 而是仍然要按照前述的規(guī)則, 即將新的輸入?yún)?shù)也置于輸出參數(shù)之前.
    的頭像 發(fā)表于 09-27 18:06 ?2496次閱讀

    Google編程風格指南(五)

    所有具有靜態(tài)存儲類型的變量 (例如靜態(tài)變量或全局變量, 參見 存儲類型) 都應(yīng)當以此方式命名. 對于其他存儲類型的變量, 如自動變量等, 這條規(guī)則是可選的. 如果不采用這條規(guī)則, 就按照一般的變量命名規(guī)則.
    的頭像 發(fā)表于 09-27 18:15 ?2420次閱讀

    Google編程風格指南(六)

    即使是英文, 也不應(yīng)將用戶界面的文本硬編碼到源代碼中, 因此非 ASCII 字符應(yīng)當很少被用到. 特殊情況下可以適當包含此類字符. 例如, 代碼分析外部數(shù)據(jù)文件時, 可以適當硬編碼數(shù)據(jù)文件中作為分隔符的非 ASCII 字符串; 更常見的是 (不需要本地化的) 單元測試代碼可能包含非 ASCII 字符串. 此類情況下, 應(yīng)使用 UTF-8 編碼, 因為很多工具都可以理解和處理 UTF-8 編碼.
    的頭像 發(fā)表于 09-27 18:18 ?2663次閱讀

    Google C++編程風格指南PDF版免費下載

    Google的項目大多使用C++開發(fā)。每一個C++程序員也都知道, C++具有很多強大的語言特性,但這種強大不可避免的導(dǎo)致它的復(fù)雜,而復(fù)雜性會使得代碼更容易出現(xiàn)bug.難于閱讀和維護。
    發(fā)表于 03-06 08:00 ?0次下載
    <b class='flag-5'>Google</b> C++<b class='flag-5'>編程</b><b class='flag-5'>風格</b><b class='flag-5'>指南</b>PDF版免費下載

    Google C++編程風格指南PDF電子書免費下載

    Google 的開源項目大多使用 C++開發(fā)。每一個 C++程序員也都知道,C++具有很多強大的語言特性,但這種強大不可避免的導(dǎo)致它的復(fù)雜,這種復(fù)雜會使得代碼更易于出現(xiàn) bug、難于閱讀和維護。本
    發(fā)表于 12-12 08:00 ?1次下載
    <b class='flag-5'>Google</b> C++<b class='flag-5'>編程</b><b class='flag-5'>風格</b><b class='flag-5'>指南</b>PDF電子書免費下載

    Verilog HIDL的RTL設(shè)計風格指南資源下載

    Verilog HIDL的RTL設(shè)計風格指南資源下載
    發(fā)表于 04-13 10:09 ?9次下載

    西門子S7-1200和S7-1500編程風格指南

    西門子S7-1200和S7-1500編程風格指南分享
    發(fā)表于 08-17 17:30 ?19次下載

    Google Python代碼風格指南

    1 背景 Python是谷歌主要使用的動態(tài)語言,本風格指導(dǎo)列舉了使用Python編程時應(yīng)該做和不該做的事項(dos nothing on first line # 縮進4個空格,首行括號后無內(nèi)容
    的頭像 發(fā)表于 11-03 10:20 ?3000次閱讀