Effective C++筆記:盡量以const、enum、inline替換#define
一.#define定義的類似函數(shù)的宏,使用時易出錯
缺點描述
這樣做的初衷是,宏看起來像函數(shù),但不會招致函數(shù)調(diào)用(function call)帶來的額外開銷。但即使你為所有實參加上小括,仍然會在使用時遭遇麻煩。舉個例子:
//?求兩個變量中最大的那個 #define?THE_MAX(a,?b)?f((a)?>?(b)???(a)?:?(b))
當(dāng)這樣使用的時候:
THE_MAX(++a,?++b);
a和b總有一個會多累加一次,這是我們不希望看到的。
替代方法
可以使用template inline函數(shù),它具有堪比宏的效率和函數(shù)的類型安全性。
inline?void?THE_MAX(const?T&?a,const?T&b) { ???f((a)?>?(b)???(a)?:?(b)) }
二.#define定義的符號不會進入記號表(symbol table),導(dǎo)致調(diào)試困難
缺點描述
如果有如下宏定義:
#define?PI?3.1415926
#define不被視為語言的一部分,PI在編譯器開始處理源碼之前就被預(yù)處理器轉(zhuǎn)移走了,于是記號PI很可能沒進入記號表。當(dāng)使用此宏但獲得一個編譯錯誤信息時,可能會帶來困惑,因為這個錯誤信息也許會提到3.1415926而不是PI。如果PI被定義在一個非你所寫的頭文件內(nèi),你肯定對3.1415926以及它來自何處毫無概念,于是你將因為追蹤它而浪費時間。
替代方法
以一個常量替換上述的宏:
const?double?pi=?3.1415926
作為一個語言常量,pi肯定會被編譯器看到,當(dāng)然就會進入記號表。此外對浮點常量而言,使用常量可能比使用#define導(dǎo)致較小量的碼,因為預(yù)處理器"盲目地將宏名稱pi替換
為3.1415926"可能導(dǎo)致目標碼(object code)出現(xiàn)多份3.1415926,若改用常量pi絕不會出現(xiàn)相同情況。
有兩個需要注意的地方:
(1) 當(dāng)定義的是常量指針,需要const兩次( const char* const iVar = "C++"),第一個const是防止值被改變,第二個const防止地址被改變。
(2) 當(dāng)定義到class內(nèi)時,需要用static來修飾這個變量,防止出現(xiàn)多個實體,代碼如下:
class?MyClass { private: ???int?i; ???doubel?d; ???static?const?int?num?=?15; ???int?scores[num]; };
三.#define不重視作用域(scope)的概念,破壞封裝性
缺點描述
一旦宏被定義,它就在其后的編譯過程中有效(除非在某處被#undef) 。這意味#define不僅不能夠用來定義class專屬常量,也不能夠提供任何封裝性,也就是說沒有所謂private #define這樣的東西。
替代方法
class?MyClass { private: ???int?i; ???doubel?d; ???enum?{?num?=?15?}; ???int?scores[num]; };
使用enum還有個好處是,如果你不想讓別人獲得一個pointer或reference指向你的某個整數(shù)常量,enum可以幫助你實現(xiàn)這個約束,因為取一個enum的地址不合法。