C++基礎知識面試必備、複習細節 (4) {Effective c++}
儘量以const,enum,inline替換#define
const double Ratio=1.65; //用該方式定義常量
#define Ratio 1.65; //儘量不要以define方式定義常量
//在類中,也可以用enum替換define
class GamePlayer{
enum{NumTurns=5}; //NumTurns就成爲5的一個記號
int scores[NumTurns];
}
//採用inline函數方式替換#define函數
//#define函數經常會引發難以察覺的錯誤
#define CALL_WITH_MAX(a,b) f((a)>(b)?(a):(b)) //用宏寫函數最好爲所有實參加上括號
//但還是有一些問題
int a=5,b=0;
CALL_WITH_MAX(++a,b); //a會被累加兩次
CALL_WITH_MAX(++a,b+10); //a會被累加一次 //這些錯誤難以發覺
template<typename T>
inline void callWithMax(const T&a,const T&b)
{
f(a>b?a:b);
}
- 總之,對於單純常量,用const對象或enum替換#define
- 對於宏函數,採用inline函數替換
儘可能使用const
-
const出現在星號左邊,表示被指物是常量;const出現在星號右側,表示指針自身是常量;兩邊都有表示被指物和指針都是常量
-
在設計類的時候,一個原則就是對於不改變數據成員的成員函數都要在後面加 const,而對於改變數據成員的成員函數不能加 const。
(1)有 const 修飾的成員函數(指 const 放在函數參數表的後面),只能讀取數據成員,不能改變數據成員;沒有 const 修飾的成員函數,對數據成員則是可讀可寫的。
(2)常量(即 const)對象可以調用 const 成員函數,而不能調用非const修飾的函數。 -
當non-const成員函數和const成員函數有相同的等價實現時,令non-const函數調用const版本避免代碼重複
確定對象被使用前已先被初始化
- 確保每一個構造函數都將對象的每一個成員初始化。儘量採用初始化列表的方式進行初始化。
- 爲了避免"跨編譯單元之初始化次序"問題,以local static對象替換non-local static對象
瞭解C++默默編寫並調用哪些函數
- 編譯器會默默爲class創建default構造函數、copy構造函數、copy assignment操作符以及析構函數
若不想使用編譯器自動生成的函數,就應該明確拒絕
- 爲了駁回編譯器自動提供的函數,可以將對應的成員函數聲明爲private並且不予以實現
- 在C++11中可以直接在成員函數聲明後面添加“= delete”,就可以阻止調用。
爲多態基類聲明virtual析構函數
帶有多態性質的base class應該聲明一個virtual析構函數,不然對其base類型指針析構時,可能會出現局部銷燬的情況,因爲無法調用到derived class的析構函數。如果classes設計目的沒有打算作爲base classes,或者不是爲了具備多態性,那麼就不應該聲明virtual析構函數
別讓異常逃離析構函數
- 析構函數不要吐出異常。如果一個被析構函數調用的函數可能拋出異常,析構函數應該捕捉任何異常,然後吞下他們或結束程序。
- 會拋出異常的代碼不要放在析構函數中
不要在構造和析構過程中調用virtual函數
構造函數和析構函數中不要調用任何虛函數,也不要調用那些調用虛函數的函數。更加根本的理由在於:在derived class對象的base class構造期間,對象的類型是base class而非derived class
令operator=返回一個reference to *this
令賦值操作符返回一個reference to *this可以實現一個連鎖賦值,保持和內置類型、標準庫一致。
在operator=中處理“自我賦值”
處理賦值時將自己賦值給自己的情況
複製對象時勿忘其每一個成分
- copying函數應該確保複製”對象內所有的成員變量“及”所有base class成分“
- 不要嘗試以某個copying函數去實現另一個copying函數。應該將共同機能放進第三個函數中,並由兩個copying函數共同調用
以對象管理資源
將資源放進對象內,利用析構函數自動調用機制確保資源被釋放。儘量使用智能指針
在資源管理中小心copying行爲
在資源管理中提供對原始資源的訪問
成對使用new和delete時要採取相同形式
如果在new表達式中使用[],delete也要使用[];如果new中不使用[],delete中也不要使用[]。特別注意typedef,很具迷惑性。
以獨立語句將newed對象置入智能指針
以獨立語句將newed對象存儲於智能指針內,不然,一旦異常拋出,有可能導致難以察覺的資源泄露。即不要在給函數傳參數時直接定義臨時(匿名)的智能指針。應該先定義好智能指針對象,再將該對象傳遞給函數。
讓接口容易被正確使用,不易被誤用
- 好的接口很容易被正確使用,不容易被誤用。你應該在你的所有接口中努力達成這些性質
- 促進正使用的辦法包括接口的一致性,以及與內置類型的行爲兼容。
- 阻止誤用的辦法包括建立新類型,限制類型上的操作,束縛對象值,以及消除客戶的資源管理責任
設計class猶如設計type
設計類時有很多問題需要思考,最好整個框架定好後再開始設計,並根據需求進行完善。
以pass-by-reference-const替換pass-by-value
- pass-by-value會造成較多的構造函數與析構函數的開銷,採用pass-by-reference-const可以避免該開銷,必須加上const
- 對於內建類型和STL迭代器、函數對象,pass-by-value是高效的
不要返回臨時對象的引用
- 不要返回一個臨時對象的引用或指針
- 不要返回堆上分配對象的引用