## 5.1. 引用參數
> Tip
> 所以按引用傳遞的參數必須加上 `const`.
定義:在 C 語言中, 如果函數需要修改變量的值, 參數必須為指針, 如 `int foo(int *pval)`. 在 C++ 中, 函數還可以聲明引用參數: `int foo(int &val)`.優點:定義引用參數防止出現 `(*pval)++` 這樣丑陋的代碼. 像拷貝構造函數這樣的應用也是必需的. 而且更明確, 不接受 `NULL` 指針.缺點:容易引起誤解, 因為引用在語法上是值變量卻擁有指針的語義.結論:函數參數列表中, 所有引用參數都必須是 `const`:
void Foo(const string &in, string *out);
事實上這在 Google Code 是一個硬性約定: 輸入參數是值參或 `const` 引用, 輸出參數為指針. 輸入參數可以是 `const` 指針, 但決不能是 非 `const` 的引用參數.
在以下情況你可以把輸入參數定義為 `const` 指針: 你想強調參數不是拷貝而來的, 在對象生存周期內必須一直存在; 最好同時在注釋中詳細說明一下. `bind2nd` 和 `mem_fun` 等 STL 適配器不接受引用參數, 這種情況下你也必須把函數參數聲明成指針類型.
## 5.2. 函數重載
> Tip
> 僅在輸入參數類型不同, 功能相同時使用重載函數 (含構造函數). 不要用函數重載模擬 [缺省函數參數](http://code.google.com/p/google-gflags/) .
定義:你可以編寫一個參數類型為 `const string&` 的函數, 然后用另一個參數類型為 `const char*` 的函數重載它:
class MyClass {
public:
void Analyze(const string &text);
void Analyze(const char *text, size_t textlen);
};
優點:通過重載參數不同的同名函數, 令代碼更加直觀. 模板化代碼需要重載, 同時為使用者帶來便利.缺點:限制使用重載的一個原因是在某個特定調用點很難確定到底調用的是哪個函數. 另一個原因是當派生類只重載了某個函數的部分變體, 會令很多人對繼承的語義產生困惑. 此外在閱讀庫的用戶代碼時, 可能會因反對使用 [缺省函數參數](http://code.google.com/p/google-gflags/) [http://code.google.com/p/google-gflags/] 造成不必要的費解.結論:如果你想重載一個函數, 考慮讓函數名包含參數信息, 例如, 使用 `AppendString()`, `AppendInt()` 而不是 `Append()`.
## 5.3. 缺省參數
> Tip
> 我們不允許使用缺省函數參數.
優點:多數情況下, 你寫的函數可能會用到很多的缺省值, 但偶爾你也會修改這些缺省值. 無須為了這些偶爾情況定義很多的函數, 用缺省參數就能很輕松的做到這點.缺點:大家通常都是通過查看別人的代碼來推斷如何使用 API. 用了缺省參數的代碼更難維護, 從老代碼復制粘貼而來的新代碼可能只包含部分參數. 當缺省參數不適用于新代碼時可能會導致重大問題.結論:我們規定所有參數必須明確指定, 迫使程序員理解 API 和各參數值的意義, 避免默默使用他們可能都還沒意識到的缺省參數.
## 5.4. 變長數組和 alloca()
> Tip
> 我們不允許使用變長數組和 `alloca()`.
優點:變長數組具有渾然天成的語法. 變長數組和 `alloca()` 也都很高效.缺點:變長數組和 `alloca()` 不是標準 C++ 的組成部分. 更重要的是, 它們根據數據大小動態分配堆棧內存, 會引起難以發現的內存越界 bugs: “在我的機器上運行的好好的, 發布后卻莫名其妙的掛掉了”.結論:使用安全的內存分配器, 如 `scoped_ptr` / `scoped_array`.
## 5.5. 友元
> Tip
> 我們允許合理的使用友元類及友元函數.
通常友元應該定義在同一文件內, 避免代碼讀者跑到其它文件查找使用該私有成員的類. 經常用到友元的一個地方是將 `FooBuilder` 聲明為 `Foo` 的友元, 以便 `FooBuilder` 正確構造 `Foo` 的內部狀態, 而無需將該狀態暴露出來. 某些情況下, 將一個單元測試類聲明成待測類的友元會很方便.
友元擴大了 (但沒有打破) 類的封裝邊界. 某些情況下, 相對于將類成員聲明為 `public`, 使用友元是更好的選擇, 尤其是如果你只允許另一個類訪問該類的私有成員時. 當然, 大多數類都只應該通過其提供的公有成員進行互操作.
## 5.6. 異常
> Tip
> 我們不使用 C++ 異常.
優點:
- 異常允許上層應用決定如何處理在底層嵌套函數中 “不可能出現的” 失敗, 不像錯誤碼記錄那么含糊又易出錯;
- 很多現代語言都使用異常. 引入異常使得 C++ 與 Python, Java 以及其它 C++ 相近的語言更加兼容.
- 許多第三方 C++ 庫使用異常, 禁用異常將導致很難集成這些庫.
- 異常是處理構造函數失敗的唯一方法. 雖然可以通過工廠函數或 `Init()` 方法替代異常, 但他們分別需要堆分配或新的 “無效” 狀態;
- 在測試框架中使用異常確實很方便.
缺點:
- 在現有函數中添加 `throw` 語句時, 你必須檢查所有調用點. 所有調用點得至少有基本的異常安全保護, 否則永遠捕獲不到異常, 只好 “開心的” 接受程序終止的結果. 例如, 如果 `f()` 調用了 `g()`, `g()` 又調用了 `h()`, `h` 拋出的異常被 `f` 捕獲, `g` 要當心了, 很可能會因疏忽而未被妥善清理.
- 更普遍的情況是, 如果使用異常, 光憑查看代碼是很難評估程序的控制流: 函數返回點可能在你意料之外. 這回導致代碼管理和調試困難. 你可以通過規定何時何地如何使用異常來降低開銷, 但是讓開發人員必須掌握并理解這些規定帶來的代價更大.
- 異常安全要求同時采用 RAII 和不同編程實踐. 要想輕松編寫正確的異常安全代碼, 需要大量的支撐機制配合. 另外, 要避免代碼讀者去理解整個調用結構圖, 異常安全代碼必須把寫持久化狀態的邏輯部分隔離到 “提交” 階段. 它在帶來好處的同時, 還有成本 (也許你不得不為了隔離 “提交” 而整出令人費解的代碼). 允許使用異常會驅使我們不斷為此付出代價, 即使我們覺得這很不劃算.
- 啟用異常使生成的二進制文件體積變大, 延長了編譯時間 (或許影響不大), 還可能增加地址空間壓力;
- 異常的實用性可能會慫恿開發人員在不恰當的時候拋出異常, 或者在不安全的地方從異常中恢復. 例如, 處理非法用戶輸入時就不應該拋出異常. 如果我們要完全列出這些約束, 這份風格指南會長出很多!
結論:
從表面上看, 使用異常利大于弊, 尤其是在新項目中. 但是對于現有代碼, 引入異常會牽連到所有相關代碼. 如果新項目允許異常向外擴散, 在跟以前未使用異常的代碼整合時也將是個麻煩. 因為 Google 現有的大多數 C++ 代碼都沒有異常處理, 引入帶有異常處理的新代碼相當困難.
鑒于 Google 現有代碼不接受異常, 在現有代碼中使用異常比在新項目中使用的代價多少要大一些. 遷移過程比較慢, 也容易出錯. 我們不相信異常的使用有效替代方案, 如錯誤代碼, 斷言等會造成嚴重負擔.
我們并不是基于哲學或道德層面反對使用異常, 而是在實踐的基礎上. 我們希望在 Google 使用我們自己的開源項目, 但項目中使用異常會為此帶來不便, 因此我們也建議不要在 Google 的開源項目中使用異常. 如果我們需要把這些項目推倒重來顯然不太現實.
對于 Windows 代碼來說, 有個 [特例](#).
(YuleFox 注: 對于異常處理, 顯然不是短短幾句話能夠說清楚的, 以構造函數為例, 很多 C++ 書籍上都提到當構造失敗時只有異常可以處理, Google 禁止使用異常這一點, 僅僅是為了自身的方便, 說大了, 無非是基于軟件管理成本上, 實際使用中還是自己決定)
## 5.7. 運行時類型識別
> Tip
> 我們禁止使用 RTTI.
定義:RTTI 允許程序員在運行時識別 C++ 類對象的類型.優點:
RTTI 在某些單元測試中非常有用. 比如進行工廠類測試時, 用來驗證一個新建對象是否為期望的動態類型.
除測試外, 極少用到.
缺點:在運行時判斷類型通常意味著設計問題. 如果你需要在運行期間確定一個對象的類型, 這通常說明你需要考慮重新設計你的類.結論:
除單元測試外, 不要使用 RTTI. 如果你發現自己不得不寫一些行為邏輯取決于對象類型的代碼, 考慮換一種方式判斷對象類型.
如果要實現根據子類類型來確定執行不同邏輯代碼, 虛函數無疑更合適. 在對象內部就可以處理類型識別問題.
如果要在對象外部的代碼中判斷類型, 考慮使用雙重分派方案, 如訪問者模式. 可以方便的在對象本身之外確定類的類型.
如果你認為上面的方法你真的掌握不了, 你可以使用 RTTI, 但務必請三思 :-) . 不要試圖手工實現一個貌似 RTTI 的替代方案, 我們反對使用 RTTI 的理由, 同樣適用于那些在類型繼承體系上使用類型標簽的替代方案.
## 5.8. 類型轉換
> Tip
> 使用 C++ 的類型轉換, 如 `static_cast<>()`. 不要使用 `int y = (int)x` 或 `int y = int(x)` 等轉換方式;
定義:C++ 采用了有別于 C 的類型轉換機制, 對轉換操作進行歸類.優點:C 語言的類型轉換問題在于模棱兩可的操作; 有時是在做強制轉換 (如 `(int)3.5`), 有時是在做類型轉換 (如 `(int)"hello"`). 另外, C++ 的類型轉換在查找時更醒目.缺點:惡心的語法.結論:
不要使用 C 風格類型轉換. 而應該使用 C++ 風格.
>
> - 用 `static_cast` 替代 C 風格的值轉換, 或某個類指針需要明確的向上轉換為父類指針時.
> - 用 `const_cast` 去掉 `const` 限定符.
> - 用 `reinterpret_cast` 指針類型和整型或其它指針之間進行不安全的相互轉換. 僅在你對所做一切了然于心時使用.
> - `dynamic_cast` 測試代碼以外不要使用. 除非是單元測試, 如果你需要在運行時確定類型信息, 說明有 [設計缺陷](#).
## 5.9. 流
> Tip
> 只在記錄日志時使用流.
定義:流用來替代 `printf()` 和 `scanf()`.優點:有了流, 在打印時不需要關心對象的類型. 不用擔心格式化字符串與參數列表不匹配 (雖然在 gcc 中使用 `printf` 也不存在這個問題). 流的構造和析構函數會自動打開和關閉對應的文件.缺點:流使得 `pread()` 等功能函數很難執行. 如果不使用 `printf` 風格的格式化字符串, 某些格式化操作 (尤其是常用的格式字符串 `%.*s`) 用流處理性能是很低的. 流不支持字符串操作符重新排序 (%1s), 而這一點對于軟件國際化很有用.結論:
不要使用流, 除非是日志接口需要. 使用 `printf` 之類的代替.
使用流還有很多利弊, 但代碼一致性勝過一切. 不要在代碼中使用流.
拓展討論:
對這一條規則存在一些爭論, 這兒給出點深層次原因. 回想一下唯一性原則 (Only One Way): 我們希望在任何時候都只使用一種確定的 I/O 類型, 使代碼在所有 I/O 處都保持一致. 因此, 我們不希望用戶來決定是使用流還是 `printf + read/write`. 相反, 我們應該決定到底用哪一種方式. 把日志作為特例是因為日志是一個非常獨特的應用, 還有一些是歷史原因.
流的支持者們主張流是不二之選, 但觀點并不是那么清晰有力. 他們指出的流的每個優勢也都是其劣勢. 流最大的優勢是在輸出時不需要關心打印對象的類型. 這是一個亮點. 同時, 也是一個不足: 你很容易用錯類型, 而編譯器不會報警. 使用流時容易造成的這類錯誤:
cout << this; // Prints the address
cout << *this; // Prints the contents
由于 `<<` 被重載, 編譯器不會報錯. 就因為這一點我們反對使用操作符重載.
有人說 `printf` 的格式化丑陋不堪, 易讀性差, 但流也好不到哪兒去. 看看下面兩段代碼吧, 實現相同的功能, 哪個更清晰?
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));
你可能會說, “把流封裝一下就會比較好了”, 這兒可以, 其他地方呢? 而且不要忘了, 我們的目標是使語言更緊湊, 而不是添加一些別人需要學習的新裝備.
每一種方式都是各有利弊, “沒有最好, 只有更適合”. 簡單性原則告誡我們必須從中選擇其一, 最后大多數決定采用 `printf + read/write`.
## 5.10. 前置自增和自減
> Tip
> 對于迭代器和其他模板對象使用前綴形式 (`++i`) 的自增, 自減運算符.
定義:對于變量在自增 (`++i` 或 `i++`) 或自減 (`--i` 或 `i--`) 后表達式的值又沒有沒用到的情況下, 需要確定到底是使用前置還是后置的自增 (自減).優點:不考慮返回值的話, 前置自增 (`++i`) 通常要比后置自增 (`i++`) 效率更高. 因為后置自增 (或自減) 需要對表達式的值 `i` 進行一次拷貝. 如果 `i` 是迭代器或其他非數值類型, 拷貝的代價是比較大的. 既然兩種自增方式實現的功能一樣, 為什么不總是使用前置自增呢?缺點:在 C 開發中, 當表達式的值未被使用時, 傳統的做法是使用后置自增, 特別是在 `for` 循環中. 有些人覺得后置自增更加易懂, 因為這很像自然語言, 主語 (`i`) 在謂語動詞 (`++`) 前.結論:對簡單數值 (非對象), 兩種都無所謂. 對迭代器和模板類型, 使用前置自增 (自減).
## 5.11. `const` 的使用
> Tip
> 我們強烈建議你在任何可能的情況下都要使用 `const`.
定義:在聲明的變量或參數前加上關鍵字 `const` 用于指明變量值不可被篡改 (如 `const int foo` ). 為類中的函數加上 `const` 限定符表明該函數不會修改類成員變量的狀態 (如 `class Foo { int Bar(char c) const; };`).優點:大家更容易理解如何使用變量. 編譯器可以更好地進行類型檢測, 相應地, 也能生成更好的代碼. 人們對編寫正確的代碼更加自信, 因為他們知道所調用的函數被限定了能或不能修改變量值. 即使是在無鎖的多線程編程中, 人們也知道什么樣的函數是安全的.缺點:`const` 是入侵性的: 如果你向一個函數傳入 `const` 變量, 函數原型聲明中也必須對應 `const` 參數 (否則變量需要 `const_cast` 類型轉換), 在調用庫函數時顯得尤其麻煩.結論:
`const` 變量, 數據成員, 函數和參數為編譯時類型檢測增加了一層保障; 便于盡早發現錯誤. 因此, 我們強烈建議在任何可能的情況下使用 `const`:
>
> - 如果函數不會修改傳入的引用或指針類型參數, 該參數應聲明為 `const`.
> - 盡可能將函數聲明為 `const`. 訪問函數應該總是 `const`. 其他不會修改任何數據成員, 未調用非 `const` 函數, 不會返回數據成員非 `const` 指針或引用的函數也應該聲明成 `const`.
> - 如果數據成員在對象構造之后不再發生變化, 可將其定義為 `const`.
然而, 也不要發了瘋似的使用 `const`. 像 `const int * const * const x;` 就有些過了, 雖然它非常精確的描述了常量 `x`. 關注真正有幫助意義的信息: 前面的例子寫成 `const int** x` 就夠了.
關鍵字 `mutable` 可以使用, 但是在多線程中是不安全的, 使用時首先要考慮線程安全.
`const` 的位置:
有人喜歡 `int const *foo` 形式, 不喜歡 `const int* foo`, 他們認為前者更一致因此可讀性也更好: 遵循了 `const` 總位于其描述的對象之后的原則. 但是一致性原則不適用于此, “不要過度使用” 的聲明可以取消大部分你原本想保持的一致性. 將 `const` 放在前面才更易讀, 因為在自然語言中形容詞 (`const`) 是在名詞 (`int`) 之前.
這是說, 我們提倡但不強制 `const` 在前. 但要保持代碼的一致性! (yospaly 注: 也就是不要在一些地方把 `const` 寫在類型前面, 在其他地方又寫在后面, 確定一種寫法, 然后保持一致.)
## 5.12. 整型
> Tip
> C++ 內建整型中, 僅使用 `int`. 如果程序中需要不同大小的變量, 可以使用 `<stdint.h>` 中長度精確的整型, 如 `int16_t`.
定義:C++ 沒有指定整型的大小. 通常人們假定 `short` 是 16 位, `int``是 32 位, ``long` 是 32 位, `long long` 是 64 位.優點:保持聲明統一.缺點:C++ 中整型大小因編譯器和體系結構的不同而不同.結論:
`<stdint.h>` 定義了 `int16_t`, `uint32_t`, `int64_t` 等整型, 在需要確保整型大小時可以使用它們代替 `short`, `unsigned long long` 等. 在 C 整型中, 只使用 `int`. 在合適的情況下, 推薦使用標準類型如 `size_t` 和 `ptrdiff_t`.
如果已知整數不會太大, 我們常常會使用 `int`, 如循環計數. 在類似的情況下使用原生類型 `int`. 你可以認為 `int` 至少為 32 位, 但不要認為它會多于 `32` 位. 如果需要 64 位整型, 用 `int64_t` 或 `uint64_t`.
對于大整數, 使用 `int64_t`.
不要使用 `uint32_t` 等無符號整型, 除非你是在表示一個位組而不是一個數值, 或是你需要定義二進制補碼溢出. 尤其是不要為了指出數值永不會為負, 而使用無符號類型. 相反, 你應該使用斷言來保護數據.
關于無符號整數:有些人, 包括一些教科書作者, 推薦使用無符號類型表示非負數. 這種做法試圖達到自我文檔化. 但是, 在 C 語言中, 這一優點被由其導致的 bug 所淹沒. 看看下面的例子:
for (unsigned int i = foo.Length()-1; i >= 0; --i) ...
上述循環永遠不會退出! 有時 gcc 會發現該 bug 并報警, 但大部分情況下都不會. 類似的 bug 還會出現在比較有符合變量和無符號變量時. 主要是 C 的類型提升機制會致使無符號類型的行為出乎你的意料.
因此, 使用斷言來指出變量為非負數, 而不是使用無符號型!
## 5.13. 64 位下的可移植性
> Tip
> 代碼應該對 64 位和 32 位系統友好. 處理打印, 比較, 結構體對齊時應切記:
-
對于某些類型, `printf()` 的指示符在 32 位和 64 位系統上可移植性不是很好. 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 規定 `%zu` |
| `ptrdiff_t` | `%d` | `%"PRIdS"` | C99 規定 `%zd` |
> 注意 `PRI*` 宏會被編譯器擴展為獨立字符串. 因此如果使用非常量的格式化字符串, 需要將宏的值而不是宏名插入格式中. 使用 `PRI*` 宏同樣可以在 `%` 后包含長度指示符. 例如, `printf("x = %30"PRIuS"\n", x)` 在 32 位 Linux 上將被展開為 `printf("x = %30" "u" "\n", x)`, 編譯器當成 `printf("x = %30u\n", x)` 處理 (yospaly 注: 這在 MSVC 6.0 上行不通, VC 6 編譯器不會自動把引號間隔的多個字符串連接一個長字符串).
-
記住 `sizeof(void *) != sizeof(int)`. 如果需要一個指針大小的整數要用 `intptr_t`.
-
你要非常小心的對待結構體對齊, 尤其是要持久化到磁盤上的結構體 (yospaly 注: 持久化 - 將數據按字節流順序保存在磁盤文件或數據庫中). 在 64 位系統中, 任何含有 `int64_t`/`uint64_t` 成員的類/結構體, 缺省都以 8 字節在結尾對齊. 如果 32 位和 64 位代碼要共用持久化的結構體, 需要確保兩種體系結構下的結構體對齊一致. 大多數編譯器都允許調整結構體對齊. gcc 中可使用 `__attribute__((packed))`. MSVC 則提供了 `#pragma pack()` 和 `__declspec(align())` (YuleFox 注, 解決方案的項目屬性里也可以直接設置).
- 創建 64 位常量時使用 LL 或 ULL 作為后綴, 如:
~~~
int64_t my_value = 0×123456789LL;
uint64_t my_mask = 3ULL << 48;
~~~
如果你確實需要 32 位和 64 位系統具有不同代碼, 可以使用 `#ifdef _LP64` 指令來切分 32/64 位代碼. (盡量不要這么做, 如果非用不可, 盡量使修改局部化)
## 5.14. 預處理宏
> Tip
> 使用宏時要非常謹慎, 盡量以內聯函數, 枚舉和常量代替之.
宏意味著你和編譯器看到的代碼是不同的. 這可能會導致異常行為, 尤其因為宏具有全局作用域.
值得慶幸的是, C++ 中, 宏不像在 C 中那么必不可少. 以往用宏展開性能關鍵的代碼, 現在可以用內聯函數替代. 用宏表示常量可被?`const`?變量代替. 用宏 “縮寫” 長變量名可被引用代替. 用宏進行條件編譯... 這個, 千萬別這么做, 會令測試更加痛苦 (`#define`?防止頭文件重包含當然是個特例).
宏可以做一些其他技術無法實現的事情, 在一些代碼庫 (尤其是底層庫中) 可以看到宏的某些特性 (如用?`#`?字符串化, 用?`##`?連接等等). 但在使用前, 仔細考慮一下能不能不使用宏達到同樣的目的.
下面給出的用法模式可以避免使用宏帶來的問題; 如果你要宏, 盡可能遵守:
> * 不要在?`.h`?文件中定義宏.
> * 在馬上要使用時才進行?`#define`, 使用后要立即?`#undef`.
> * 不要只是對已經存在的宏使用#undef,選擇一個不會沖突的名稱;
> * 不要試圖使用展開后會導致 C++ 構造不穩定的宏, 不然也至少要附上文檔說明其行為.
## 5.15. 0 和 NULL
> Tip
> 整數用?`0`, 實數用?`0.0`, 指針用?`NULL`, 字符 (串) 用?`'\0'`.
整數用?`0`, 實數用?`0.0`, 這一點是毫無爭議的.
對于指針 (地址值), 到底是用?`0`?還是?`NULL`, Bjarne Stroustrup 建議使用最原始的?`0`. 我們建議使用看上去像是指針的?`NULL`, 事實上一些 C++ 編譯器 (如 gcc 4.1.0) 對?`NULL`?進行了特殊的定義, 可以給出有用的警告信息, 尤其是?`sizeof(NULL)`?和?`sizeof(0)`?不相等的情況.
字符 (串) 用?`'\0'`, 不僅類型正確而且可讀性好.
## 5.16. sizeof
> Tip
> 盡可能用?`sizeof(varname)`?代替?`sizeof(type)`.
使用?`sizeof(varname)`?是因為當代碼中變量類型改變時會自動更新. 某些情況下?`sizeof(type)`?或許有意義, 但還是要盡量避免, 因為它會導致變量類型改變后不能同步.
~~~
Struct data;
Struct data; memset(&data, 0, sizeof(data));
~~~
> Warning
> memset(&data, 0, sizeof(Struct));
## 5.17. Boost 庫
> Tip
> 只使用 Boost 中被認可的庫.
定義:
[Boost 庫集](http://www.boost.org/)?是一個廣受歡迎, 經過同行鑒定, 免費開源的 C++ 庫集.
優點:
Boost代碼質量普遍較高, 可移植性好, 填補了 C++ 標準庫很多空白, 如型別的特性, 更完善的綁定器, 更好的智能指針, 同時還提供了?`TR1`?(標準庫擴展) 的實現.
缺點:
某些 Boost 庫提倡的編程實踐可讀性差, 比如元編程和其他高級模板技術, 以及過度 “函數化” 的編程風格.
結論:
為了向閱讀和維護代碼的人員提供更好的可讀性, 我們只允許使用 Boost 一部分經認可的特性子集. 目前允許使用以下庫:
> * [Compressed Pair](http://www.boost.org/libs/utility/compressed_pair.htm)?:?`boost/compressed_pair.hpp`
> * [Pointer Container](http://www.boost.org/libs/ptr_container/)?:?`boost/ptr_container`?(序列化除外)
> * [Array](http://www.boost.org/libs/array/)?:?`boost/array.hpp`
> * [The Boost Graph Library (BGL)](http://www.boost.org/libs/graph/)?:?`boost/graph`?(序列化除外)
> * [Property Map](http://www.boost.org/libs/property_map/)?:?`boost/property_map.hpp`
> * [Iterator](http://www.boost.org/libs/iterator/)?中處理迭代器定義的部分 :?`boost/iterator/iterator_adaptor.hpp`,?`boost/iterator/iterator_facade.hpp`, 以及?`boost/function_output_iterator.hpp`
我們正在積極考慮增加其它 Boost 特性, 所以列表中的規則將不斷變化.
- Google 開源項目風格指南 (中文版)
- C++ 風格指南
- 0. 扉頁
- 1. 頭文件
- 2. 作用域
- 3. 類
- 4. 來自 Google 的奇技
- 5. 其他 C++ 特性
- 6. 命名約定
- 7. 注釋
- 8. 格式
- 9. 規則特例
- 10. 結束語
- Objective-C 風格指南
- Google Objective-C Style Guide 中文版
- 留白和格式
- 命名
- 注釋
- Cocoa 和 Objective-C 特性
- Cocoa 模式
- Python 風格指南
- Google Python 風格指南 - 中文版
- 背景
- Python語言規范
- Python風格規范
- 臨別贈言
- JSON 風格指南
- 簡介
- 定義
- 一般準則
- 屬性名準則
- 屬性值準則
- 屬性值數據類型
- JSON結構和保留屬性名
- 頂級保留屬性名稱
- data對象的保留屬性名
- 用于分頁的保留屬性名
- 用于鏈接的保留屬性名
- 錯誤對象中的保留屬性名
- 屬性順序
- 示例
- 附錄