《Effective C++》筆記

01:視c++爲一個語言聯邦

爲了理解C++,必需要認識其主要的次語言:c++

  • C
    說到底C++還是以C爲基礎。區塊,語句,預處理器,內置數據類型,數組,指針通通來自C。
  • Object-Oreinted C++
    這一部分是面向對象設計之古典守則在C++上的最直接實施。類,封裝,繼承,多態,virtual函數等等...
  • Template C++
    這是C++泛型編程部分。
  • STL
    STL是個template程序庫。包含容器(containers),迭代器(iterators),算法(algorithms)以及函數對象(function objects)...
    這四個次語言,當你從某個次語言切換到另外一個,致使高效編程守則要求你改變策略。C++高效編程守則視情況而變化,取決於你使用C++的哪一部分。

    例如:當對內置(C-like)類型而言,pass-by-value比pass-by-reference高效。但當你從C part of C++移往Object-Oriented C++,因爲user-defined構造函數和析構函數的存在,pass-by-reference-to-const每每更好。運用template C++ 時尤爲如此。然而對STL的迭代器和函數對象而言,舊式的pass-by-value守則再次適用。算法

    請記住

  • C++高效編程守則視情況而變化,取決於你使用C++的哪一部分。編程

02:儘可能以const,enum,inline替換#define

#define M 1.1

記號M也許從未被編譯器看見,也許在編譯器開始處理源碼以前它就被預處理器移走了。所以M可能壓根就就沒進入符號表(symbol table)。當你使用該常量但產生編譯錯誤時,錯誤信息可能只提到1.1而不是M。若被定義在某個頭文件中,就很難發現錯誤所在。
解決之道:數組

const double M=1.1;

做爲語言常量,M確定會被編譯器看到,天然也就必定會進入符號表。另外,使用常量還能夠避免宏替換帶來的多份目標碼(object code)問題。安全

兩種特殊狀況函數

  1. 定義常量指針
    因爲常量表達式一般被放在頭文件內,所以有必要將指針(不只是指針所指之物)聲明爲const。
    例如:
const char* const authorName="Scott Meyers";
  1. class專屬常量
    爲了限制做用域於class內,必須讓它成爲class的一個成員,爲了確保只有一份,必須加上static修飾符。
class GamePlayer
{
    static const int NumTurns=5;
    int scores[Numturns];
};

若是你須要取這個常量的地址或者是編譯器堅持要看到一個定義式,你就必須在實現文件中提供以下定義:學習

const int GmaePlayer::NumTurns;

若是編譯器不支持static成員在聲明式上得到初始值,那麼只好放在定義式上。但當你在class編譯期間須要一個class常量值,能夠採用the enum hackthis

class GamePlayer
{
    enum{NumTurns=5};
    int scores[Numturns];
};

關於the enum hack,有幾點須要瞭解:設計

  • 對一個enum取地址是不合法的,所以能夠做爲不容許獲取pointer或reference的約束。
  • 是模板元編程的基礎技術(template metaprogramming)

另外一個問題是用#define實現宏。(這裏沒有使用原書中的例子)指針

#define SUB(a,b) a-b

對於以上宏定義,試問F(4-1,3)*2結果爲多少?按照直觀理解,你可能會理所固然的認爲是0。但當咱們寫出展開式後:4-1-2*2,顯然結果是-1。
爲了不這種問題,只好給參數加上括號:

#define SUB(a,b) ((a)-(b))

不管什麼時候當你寫出這種宏,就必須爲全部實參加上小括號,但即便是加上小括號,有時也會出現問題。
如今咱們可使用template inline解決這一點:

template<typename T>
inline auto SUB(const T& a,const T& b) -> decltype(a-b)
{
    return a-b;
}

請記住

  • 對於單純常量,最好以const對象或enums替換#defines。
  • 對於形似函數的宏,最好改用inline函數替換之。

03:儘量使用const

04:肯定對象被使用前已先被初始化

05:瞭解C++默默編寫並調用哪些函數

06:若不想使用編譯器自動生成的函數,就該明確拒絕

07:爲多態基類聲明virtual析構函數

08:別讓異常逃離析構函數

09:毫不在構造和析構的過程當中調用virtual函數

10:令operator= 返回一個reference to *this

11:在operator=中處理自我賦值

12:複製對象時勿忘其每個成分

13:以對象管理資源(RAII)

14:在資源類中當心coping行爲

15:在資源類中提供對原始資源的訪問

16:成對使用new和delete時要採用相同形式

17:以獨立語句將newed對象置入智能指針

18:讓接口容易被正確使用,不易被誤用

19:設計class猶如設計type

20:寧以pass-by-reference-to-const替換pass-by-value

21:必須返回對象時,別妄想返回其reference

22:將成員變量聲明爲private

23:寧以non-member、non-friend替換member函數

24:若全部參數皆要類型轉換,請爲此採用non-member函數

25:考慮寫出一個不出異常的swap函數

26:儘量延後變量定義式的出現時間

27:儘可能少作轉型操做

28:避免返回handles指向對象內部成分

29:爲異常安全而努力是值得的

30:透徹瞭解inlining的裏裏外外

31:將文件間的編譯依存關係降到最低

32:肯定你的public繼承塑模出is-a關係

33:避免遮掩繼承而來的名稱

34;區分接口繼承和實現繼承

35:考慮virtual函數之外的其餘選擇

36:毫不從新定義繼承來的的non-virtual函數

37:毫不從新定義繼承而來的缺省參數值

38:經過複合塑模出has-a或根據某物實現出

39:明智而審慎地使用private繼承

40:明智而審慎地使用多重繼承

41:瞭解隱式接口和編譯器多態

42:解誒typename的雙重意義

43:學習處理模板化基類內的名稱

44:將與參數無關的代碼抽離template

45:運用成員模板接受全部兼容類型

46:須要類型轉換時請爲模板定義非成員函數

47:請使用traits classes表現類型信息

48:認識template元編程

49:瞭解new-handler的行爲

50:瞭解new和delete的合理替換時機

51:編寫new和delete時需固守常規

52:寫了placement new 也要寫placement delete

53:不要輕視編譯器的警告

54:讓本身熟悉包括TR1在內的標準程序庫

55:讓本身熟悉boost

相關文章
相關標籤/搜索