Google C++程式設計風格指南(四):智慧指標和其他C++特性

yangdelong發表於2009-10-10

http://www.kuqin.com/language/20080721/11905.html

 

1. 對於智慧指標,安全第一、方便第二,儘可能區域性化(scoped_ptr); 2. 引用形參加上const,否則使用指標形參;3. 函式過載的使用要清晰、易讀;4. 鑑於容易誤用,禁止使用預設函式引數(值得商榷);5. 禁止使用變長陣列;6. 合理使用友元……

 

  • Google特有的風情

Google有很多自己實現的使C++程式碼更加健壯的技巧、功能,以及有異於別處的C++的使用方式。

1. 智慧指標(Smart Pointers)

如果確實需要使用智慧指標的話,scoped_ptr完全可以勝任。在非常特殊的情況下,例如對STL容器中物件,你應該只使用std::tr1::shared_ptr,任何情況下都不要使用auto_ptr。

“智慧”指標看上去是指標,其實是附加了語義的物件。以scoped_ptr為例,scoped_ptr被銷燬時,刪除了它所指向的物件。shared_ptr也是如此,而且,shared_ptr實現了引用計數(reference-counting),從而只有當它所指向的最後一個物件被銷燬時,指標才會被刪除。

一般來說,我們傾向於設計物件隸屬明確的程式碼,最明確的物件隸屬是根本不使用指標,直接將物件作為一個域(field)或區域性變數使用。另一種極端是引用計數指標不屬於任何物件,這樣設計的問題是容易導致迴圈引用或其他導致物件無法刪除的詭異條件,而且在每一次拷貝或賦值時連原子操作都會很慢。

雖然不推薦這麼做,但有些時候,引用計數指標是最簡單有效的解決方案。

譯者注:看來,Google所謂的不同之處,在於儘量避免使用智慧指標:D,使用時也儘量區域性化,並且,安全第一。

  • 其他C++特性

1. 引用引數(Reference Arguments)

所以按引用傳遞的引數必須加上const。

定義:在C語言中,如果函式需要修改變數的值,形參(parameter)必須為指標,如int foo(int *pval)。在C++中,函式還可以宣告引用形參:int foo(int &val)。

優點:定義形參為引用避免了像(*pval)++這樣醜陋的程式碼,像拷貝建構函式這樣的應用也是必需的,而且不像指標那樣不接受空指標NULL。

缺點:容易引起誤解,因為引用在語法上是值卻擁有指標的語義。

結論:

函式形參表中,所有引用必須是const:

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

事實上這是一個硬性約定:輸入引數為值或常數引用,輸出引數為指標;輸入引數可以是常數指標,但不能使用非常數引用形參。

在強調引數不是拷貝而來,在物件生命期內必須一直存在時可以使用常數指標,最好將這些在註釋中詳細說明。bind2nd和mem_fun等STL介面卡不接受引用形參,這種情況下也必須以指標形參宣告函式。

2. 函式過載(Function Overloading)

僅在輸入引數型別不同、功能相同時使用過載函式(含建構函式),不要使用函式過載模仿預設函式引數。

定義:可以定義一個函式引數型別為const string&,並定義其過載函式型別為const char*。

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

優點:通過過載不同引數的同名函式,令程式碼更加直觀,模板化程式碼需要過載,同時為訪問者帶來便利。

缺點:限制使用過載的一個原因是在特定呼叫處很難確定到底呼叫的是哪個函式,另一個原因是當派生類只過載函式的部分變數會令很多人對繼承語義產生困惑。此外在閱讀庫的客戶端程式碼時,因預設函式引數造成不必要的費解。

結論:如果你想過載一個函式,考慮讓函式名包含引數資訊,例如,使用AppendString()、AppendInt()而不是Append()。

3. 預設引數(Default Arguments)

禁止使用預設函式引數。

優點:經常用到一個函式帶有大量預設值,偶爾會重寫一下這些值,預設引數為很少涉及的例外情況提供了少定義一些函式的方便。

缺點:大家經常會通過檢視現有程式碼確定如何使用API,預設引數使得複製貼上以前的程式碼難以呈現所有引數,當預設引數不適用於新程式碼時可能導致重大問題。

結論:所有引數必須明確指定,強制程式設計師考慮API和傳入的各引數值,避免使用可能不為程式設計師所知的預設引數。

4. 變長陣列和alloca(Variable-Length Arrays and alloca())

禁止使用變長陣列和alloca()。

優點:變長陣列具有渾然天成的語法,變長陣列和alloca()也都很高效。

缺點:變長陣列和alloca()不是標準C++的組成部分,更重要的是,它們在堆疊(stack)上根據資料分配大小可能導致難以發現的記憶體洩漏:“在我的機器上執行的好好的,到了產品中卻莫名其妙的掛掉了”。

結論:

使用安全的分配器(allocator),如scoped_ptr/scoped_array。

5. 友元(Friends)

允許合理使用友元類及友元函式。

通常將友元定義在同一檔案下,避免讀者跑到其他檔案中查詢其對某個類私有成員的使用。經常用到友元的一個地方是將FooBuilder宣告為Foo的友元,FooBuilder以便可以正確構造Foo的內部狀態,而無需將該狀態暴露出來。某些情況下,將一個單元測試用類宣告為待測類的友元會很方便。

友元延伸了(但沒有打破)類的封裝界線,當你希望只允許另一個類訪問某個成員時,使用友元通常比將其宣告為public要好得多。當然,大多數類應該只提供公共成員與其互動。

6. 異常(Exceptions

不要使用C++異常。

優點:

1) 異常允許上層應用決定如何處理在底層巢狀函式中發生的“不可能發生”的失敗,不像出錯程式碼的記錄那麼模糊費解;

2) 應用於其他很多現代語言中,引入異常使得C++與Python、Java及其他與C++相近的語言更加相容;

3) 許多C++第三方庫使用異常,關閉異常將導致難以與之結合;

4) 異常是解決建構函式失敗的唯一方案,雖然可以通過工廠函式(factory function)或Init()方法模擬異常,但他們分別需要堆分配或新的“非法”狀態;

5) 在測試框架(testing framework)中,異常確實很好用。

缺點:

1) 在現有函式中新增throw語句時,必須檢查所有呼叫處,即使它們至少具有基本的異常安全保護,或者程式正常結束,永遠不可能捕獲該異常。例如:if f() calls g() calls h()h丟擲被f捕獲的異常,g就要當心了,避免沒有完全清理;

2) 通俗一點說,異常會導致程式控制流(control flow)通過檢視程式碼無法確定:函式有可能在不確定的地方返回,從而導致程式碼管理和除錯困難,當然,你可以通過規定何時何地如何使用異常來最小化的降低開銷,卻給開發人員帶來掌握這些規定的負擔;

3) 異常安全需要RAII和不同編碼實踐。輕鬆、正確編寫異常安全程式碼需要大量支撐。允許使用異常;

4) 加入異常使二進位制執行程式碼體積變大,增加了編譯時長(或許影響不大),還可能增加地址空間壓力;

5) 異常的實用性可能會刺激開發人員在不恰當的時候丟擲異常,或者在不安全的地方從異常中恢復,例如,非法使用者輸入可能導致丟擲異常。如果允許使用異常會使得這樣一篇程式設計風格指南長出很多(譯者注,這個理由有點牽強:-()!

結論:

從表面上看,使用異常利大於弊,尤其是在新專案中,然而,對於現有程式碼,引入異常會牽連到所有依賴程式碼。如果允許異常在新專案中使用,在跟以前沒有使用異常的程式碼整合時也是一個麻煩。因為Google現有的大多數C++程式碼都沒有異常處理,引入帶有異常處理的新程式碼相當困難。

鑑於Google現有程式碼不接受異常,在現有程式碼中使用異常比在新專案中使用的代價多少要大一點,遷移過程會比較慢,也容易出錯。我們也不相信異常的有效替代方案,如錯誤程式碼、斷言等,都是嚴重負擔。

我們並不是基於哲學或道德層面反對使用異常,而是在實踐的基礎上。因為我們希望使用Google上的開源專案,但專案中使用異常會為此帶來不便,因為我們也建議不要在Google上的開源專案中使用異常,如果我們需要把這些專案推倒重來顯然不太現實。

對於Windows程式碼來說,這一點有個例外(等到最後一篇吧:D)。

譯者注:對於異常處理,顯然不是短短几句話能夠說清楚的,以建構函式為例,很多C++書籍上都提到當構造失敗時只有異常可以處理,Google禁止使用異常這一點,僅僅是為了自身的方便,說大了,無非是基於軟體管理成本上,實際使用中還是自己決定。

7. 執行時型別識別(Run-Time Type Information, RTTI

我們禁止使用RTTI。

定義:RTTI允許程式設計師在執行時識別C++類物件的型別。

優點:

RTTI在某些單元測試中非常有用,如在進行工廠類測試時用於檢驗一個新建物件是否為期望的動態型別。

除測試外,極少用到。

缺點:執行時識別型別意味著設計本身有問題,如果你需要在執行期間確定一個物件的型別,這通常說明你需要重新考慮你的類的設計。

結論:

除單元測試外,不要使用RTTI,如果你發現需要所寫程式碼因物件型別不同而動作各異的話,考慮換一種方式識別物件型別。

虛擬函式可以實現隨子類型別不同而執行不同程式碼,工作都是交給物件本身去完成。

如果工作在物件之外的程式碼中完成,考慮雙重分發方案,如Visitor模式,可以方便的在物件本身之外確定類的型別。

如果你認為上面的方法你掌握不了,可以使用RTTI,但務必請三思,不要去手工實現一個貌似RTTI的方案(RTTI-like workaround),我們反對使用RTTI,同樣反對貼上型別標籤的貌似類繼承的替代方案(譯者注,使用就使用吧,不使用也不要造輪子:D)。

8. 型別轉換(Casting

使用static_cast<>()等C++的型別轉換,不要使用int y = (int)xint y = int(x);

定義:C++引入了有別於C的不同型別的型別轉換操作。

優點:C語言的型別轉換問題在於操作比較含糊:有時是在做強制轉換(如(int)3.5),有時是在做型別轉換(如(int)"hello")。另外,C++的型別轉換查詢更容易、更醒目。

缺點:語法比較噁心(nasty)。

結論:使用C++風格而不要使用C風格型別轉換。

1) static_cast:和C風格轉換相似可做值的強制轉換,或指標的父類到子類的明確的向上轉換;

2) const_cast:移除const屬性;

3) reinterpret_cast:指標型別和整型或其他指標間不安全的相互轉換,僅在你對所做一切瞭然於心時使用;

4) dynamic_cast:除測試外不要使用,除單元測試外,如果你需要在執行時確定型別資訊,說明設計有缺陷(參考RTTI)。

9. 流(Streams

只在記錄日誌時使用流。

定義:流是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

10. 前置自增和自減(Preincrement and Predecrement

對於迭代器和其他模板物件使用字首形式(++i)的自增、自減運算子。

定義:對於變數在自增(++ii++)或自減(--ii--)後表示式的值又沒有沒用到的情況下,需要確定到底是使用前置還是後置的自增自減。

優點:不考慮返回值的話,前置自增(++i)通常要比後置自增(--i)效率更高,因為後置的自增自減需要對錶達式的值i進行一次拷貝,如果i是迭代器或其他非數值型別,拷貝的代價是比較大的。既然兩種自增方式動作一樣(譯者注,不考慮表示式的值,相信你知道我在說什麼),為什麼不直接使用前置自增呢?

缺點:C語言中,當表示式的值沒有使用時,傳統的做法是使用後置自增,特別是在for迴圈中,有些人覺得後置自增更加易懂,因為這很像自然語言,主語(i)在謂語動詞(++)前。

結論:對簡單數值(非物件)來說,兩種都無所謂,對迭代器和模板型別來說,要使用前置自增(自減)。

11. const的使用(Use of const

我們強烈建議你在任何可以使用的情況下都要使用const

定義:在宣告的變數或引數前加上關鍵字const用於指明變數值不可修改(如const int foo),為類中的函式加上const限定表明該函式不會修改類成員變數的狀態(如class Foo { int Bar(char c) const; };)。

優點:人們更容易理解變數是如何使用的,編輯器可以更好地進行型別檢測、更好地生成程式碼。人們對編寫正確的程式碼更加自信,因為他們知道所呼叫的函式被限定了能或不能修改變數值。即使是在無鎖的多執行緒程式設計中,人們也知道什麼樣的函式是安全的。

缺點:如果你向一個函式傳入const變數,函式原型中也必須是const的(否則變數需要const_cast型別轉換),在呼叫庫函式時這尤其是個麻煩。

結論const變數、資料成員、函式和引數為編譯時型別檢測增加了一層保障,更好的儘早發現錯誤。因此,我們強烈建議在任何可以使用的情況下使用const

1) 如果函式不會修改傳入的引用或指標型別的引數,這樣的引數應該為const

2) 儘可能將函式宣告為const,訪問函式應該總是const,其他函式如果不會修改任何資料成員也應該是const,不要呼叫非const函式,不要返回對資料成員的非const指標或引用;

3) 如果資料成員在物件構造之後不再改變,可將其定義為const

然而,也不要對const過度使用,像const int * const * const x;就有些過了,即便這樣寫精確描述了x,其實寫成const int** x就可以了。

關鍵字mutable可以使用,但是在多執行緒中是不安全的,使用時首先要考慮執行緒安全。

const位置

有人喜歡int const *foo形式不喜歡const int* foo,他們認為前者更加一致因此可讀性更好:遵循了const總位於其描述的物件(int)之後的原則。但是,一致性原則不適用於此,“不要過度使用”的權威抵消了一致性使用。將const放在前面才更易讀,因為在自然語言中形容詞(const)是在名詞(int)之前的。

這是說,我們提倡const在前,並不是要求,但要兼顧程式碼的一致性!

12. 整型(Integer Types

C++內建整型中,唯一用到的是int,如果程式中需要不同大小的變數,可以使用<stdint.h>中的精確寬度(precise-width)的整型,如int16_t

定義:C++沒有指定整型的大小,通常人們認為short是16位,int是32位,long是32位,long long是64位。

優點:保持宣告統一。

缺點:C++中整型大小因編譯器和體系結構的不同而不同。

結論

<stdint.h>定義了int16_tuint32_tint64_t等整型,在需要確定大小的整型時可以使用它們代替shortunsigned long long等,在C整型中,只使用int。適當情況下,推薦使用標準型別如size_tptrdiff_t

最常使用的是,對整數來說,通常不會用到太大,如迴圈計數等,可以使用普通的int。你可以認為int至少為32位,但不要認為它會多於32位,需要64位整型的話,可以使用int64_tuint64_t

對於大整數,使用int64_t

不要使用uint32_t等無符號整型,除非你是在表示一個位組(bit pattern)而不是一個數值。即使數值不會為負值也不要使用無符號型別,使用斷言(assertion,譯者注,這一點很有道理,計算機只會根據變數、返回值等有無符號確定數值正負,仍然無法確定對錯)來保護資料。

無符號整型

有些人,包括一些教科書作者,推薦使用無符號型別表示非負數,型別表明了數值取值形式。但是,在C語言中,這一優點被由其導致的bugs所淹沒。看看:

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

 

上述程式碼永遠不會終止!有時gcc會發現該bug並報警,但通常不會。類似的bug還會出現在比較有符合變數和無符號變數時,主要是C的型別提升機制(type-promotion scheme,C語言中各種內建型別之間的提升轉換關係)會致使無符號型別的行為出乎你的意料。

因此,使用斷言宣告變數為非負數,不要使用無符號型。

13. 64位下的可移植性(64-bit Portability

程式碼在64位和32位的系統中,原則上應該都比較友好,尤其對於輸出、比較、結構對齊(structure alignment)來說:

1) 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)

2) 記住sizeof(void *) != sizeof(int),如果需要一個指標大小的整數要使用intptr_t

3) 需要對結構對齊加以留心,尤其是對於儲存在磁碟上的結構體。在64位系統中,任何擁有int64_t/uint64_t成員的類/結構體將預設被處理為8位元組對齊。如果32位和64位程式碼共用磁碟上的結構體,需要確保兩種體系結構下的結構體的對齊一致。大多數編譯器提供了調整結構體對齊的方案。gcc中可使用__attribute__((packed)),MSVC提供了#pragma pack()__declspec(align())(譯者注,解決方案的專案屬性裡也可以直接設定)。

4) 建立64位常量時使用LLULL作為字尾,如:

 

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

 

5) 如果你確實需要32位和64位系統具有不同程式碼,可以在程式碼變數前使用。(儘量不要這麼做,使用時儘量使修改區域性化)。

14. 預處理巨集(Preprocessor Macros

使用巨集時要謹慎,儘量以行內函數、列舉和常量代替之。

巨集意味著你和編譯器看到的程式碼是不同的,因此可能導致異常行為,尤其是當巨集存在於全域性作用域中。

值得慶幸的是,C++中,巨集不像C中那麼必要。巨集內聯效率關鍵程式碼(performance-critical code)可以行內函數替代;巨集儲存常量可以const變數替代;巨集“縮寫”長變數名可以引用替代;使用巨集進行條件編譯,這個……,最好不要這麼做,會令測試更加痛苦(#define防止標頭檔案重包含當然是個例外)。

巨集可以做一些其他技術無法實現的事情,在一些程式碼庫(尤其是底層庫中)可以看到巨集的某些特性(如字串化(stringifying,譯者注,使用#)、連線(concatenation,譯者注,使用##)等等)。但在使用前,仔細考慮一下能不能不使用巨集實現同樣效果。

譯者注:關於巨集的高階應用,可以參考《C語言巨集的高階應用

下面給出的用法模式可以避免一些使用巨集的問題,供使用巨集時參考:

1) 不要在.h檔案中定義巨集;

2) 使用前正確#define,使用後正確#undef

3) 不要只是對已經存在的巨集使用#undef,選擇一個不會衝突的名稱;

4) 不使用會導致不穩定的C++構造(unbalanced C++ constructs,譯者注)的巨集,至少文件說明其行為。

15. 0和NULL(0 and NULL

整數用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',不僅型別正確而且可讀性好。

16. sizeof(sizeof

儘可能用sizeof(varname)代替sizeof(type)

使用sizeof(varname)是因為當變數型別改變時程式碼自動同步,有些情況下sizeof(type)或許有意義,還是要儘量避免,如果變數型別改變的話不能同步。

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

 

17. Boost庫(Boost

只使用Boost中被認可的庫。

定義:Boost庫集是一個非常受歡迎的、同級評議的(peer-reviewed)、免費的、開源的C++庫。

優點:Boost程式碼質量普遍較高、可移植性好,填補了C++標準庫很多空白,如型別特性(type traits)、更完善的繫結(binders)、更好的智慧指標,同時還提供了TR1(標準庫的擴充套件)的實現。

缺點:某些Boost庫提倡的程式設計實踐可讀性差,像元程式(metaprogramming)和其他高階模板技術,以及過度“函式化”("functional")的程式設計風格。

結論:為了向閱讀和維護程式碼的人員提供更好的可讀性,我們只允許使用Boost特性的一個成熟子集,當前,這些庫包括:

1) Compressed Pairboost/compressed_pair.hpp

2) Pointer Containerboost/ptr_container不包括ptr_array.hpp和序列化(serialization)。

我們會積極考慮新增可以的Boost特性,所以不必拘泥於該規則。

______________________________________

譯者:關於C++特性的注意事項,總結一下:

1. 對於智慧指標,安全第一、方便第二,儘可能區域性化(scoped_ptr)

2. 引用形參加上const,否則使用指標形參;

3. 函式過載的使用要清晰、易讀;

4. 鑑於容易誤用,禁止使用預設函式引數(值得商榷);

5. 禁止使用變長陣列;

6. 合理使用友元;

7. 為了方便程式碼管理,禁止使用異常(值得商榷);

8. 禁止使用RTTI,否則重新設計程式碼吧;

9. 使用C++風格的型別轉換,除單元測試外不要使用dynamic_cast;

10. 使用流還printf + read/write,it is a problem;

11. 能用前置自增/減不用後置自增/減;

12. const能用則用,提倡const在前;

13. 使用確定大小的整型,除位組外不要使用無符號型;

14. 格式化輸出及結構對齊時,注意32位和64位的系統差異;

15. 除字串化、連線外儘量避免使用巨集;

16. 整數用0,實數用0.0,指標用NULL,字元(串)用'/0';

17. 用sizeof(varname)代替sizeof(type);

18. 只使用Boost中被認可的庫。

來自:http://www.cppblog.com/Fox/archive/2008/07/21/56760.html
原文:Google C++ Style Guide

相關文章