寫在前面:
最近吃了安利開始啃Scott Meyers的Effective C++第三版,書中乾貨不少,非常值得深思借鑑。但是也有點太多了(→_→),腦子實在裝不下,就想寫成部落格一樣的讀書筆記同時分享給大家,再也是為了第二次讀的時候,能給自己留一點印象。
一共有55篇,希望自己可以堅持下來。如果有不恰當之處,還請大家及時指出。以及我會保持語言簡練,不過多解釋相關概念,因此適合對C++有一定基礎的讀者。
本篇關鍵詞: 全域性變數,宏(#define)
守則01:把C++看做一個語言的集合,而不是單一的語言
“C++ is a federation of languages”
早期的C++只是叫“C with classes”,但發展到今天已經成為一個多重泛型程式語言(Multi-paradigm programming language),它具有4種“子語言”:
C
面向物件的C++
模板C++
STL
高效的C++程式設計守則取決於你所使用的“子語言”
例如
:
在C中,一般使用值傳遞 (Pass by value)
在面向物件的C++和模板C++中,使用常量引用傳遞 (Pass by const reference)更加高效
對於STL,因為迭代器是基於指標構造而成,直接使用值傳遞即可
在不同的“子語言”中需要你用不同的策略,而非自始至終單一的方法,記住這一點對於理解學習C++這樣功能強大的語言十分有幫助
守則02:儘量使用const, enum, inline, 減少宏變數#define的使用
①或者說,儘量多用編譯器,少用預處理器
“Prefer the compiler to the preprocessor”
例如:
#define A 1。653
在上面這個語句中,字串‘A’是不會被編譯器看到的,而編譯器看到的是‘1。653’,這就會導致在除錯過程中,編譯器的錯誤資訊只顯示‘1。653’而不是‘A’,讓你不知從何下手。
解決方法:定義全域性常量
const double A = 1。653;
使用全域性常量還有一個好處:預處理器只會把每次對‘A’的引用變成‘1。653’而不管其是否已經存在,這就導致多次引用‘A’會造成多個重複物件出現在目的碼中(Object code),造成資源浪費。
②當定義或宣告全域性變數時,常數指標和類的常數需要另加考慮
對於指標
對於指標要把指標本身和它指向的資料都定義為const,例如
const char* const myWord = “Hello”;
在C++中可以更方便地使用std::string這樣基於char*型別的推廣,例如
const std::string myWord(“Hello”);
對於類的常數
宣告為類的私有靜態成員,這樣既保證變數只能被這個類的物件接觸到,又不會生成多個複製
class Player{
private:
static const int numPlayer = 5;
……。。
注意
,因為此處是類的成員聲明範圍內,所以上面只是變數的宣告和初始化,而並非定義,因此如果想獲取變數的地址,需要在別處另加定義。這個定義不能有任何賦值語句,因為在類內已經規定為const:
const int Player::numPlayer;
③列舉技巧
(the enum hack):
試想當你在一個類內宣告某變數,但你的編譯器不允許在宣告時賦值初始化,同時接下來的某個語句卻需要用到這個變數的具體數值,例如:
int noPlayer;
int scores[noPlayer];
此時編譯器便會報錯,需要在編譯期間noPlayer有具體數值,這個時候就需要使用如下技巧:
enum {noPlayer = 5};
int scores[noPlayer];
這樣編譯器就能順利透過,因為enum可以被當成int型別來使用
但注意enum型別在記憶體中沒有實體,無法取得enum型別的地址,因此這個方法更相當於取一個本地的#define數值
④對於#define的宏函式,儘量使用inline修飾的函式來代替#define
inline關鍵字用來建議編譯器把某頻繁呼叫的函式當做行內函數,即在每次函式呼叫時,直接把函式程式碼放在函式呼叫語句的地址,減少堆疊浪費。
如果為了減少堆疊資源的使用,把某個頻繁呼叫的函式規定為宏,例如用a和b的最大值來呼叫某函式f:
#define CALL_MAX(a,b) f((a) > (b) ? (a) : (b))
但這樣的做法其實相當不好,因為第一需要把所有引數用小括號擴起來,這樣的程式碼相當不雅觀,而且也會導致未知的結果:
int a=5, b=0;
CALL_MAX(++a, b); //a增加了一次
CALL_MAX(++a, b+10); //a增加了兩次
解決方法:
template
inline void callMax(const T& a, const T& b){
f(a>b ? a:b);
}
這樣既保證了堆疊不會枯竭,又讓程式碼更加美觀
總結:宏常量用全域性的const或者enum來替換,宏函式用inline修飾的函式來替換