『Effective C++』読書ノート第一章:c++に慣れる


Accustoming Youself to C++
条項1.c++を言語連邦と見なす
C++は多重モデルプログラミング言語であり、同時にプロセス形式、オブジェクト向け形式、関数形式、汎用形式、メタプログラミング形式をサポートする.c++は言語連邦であり、以下の4つの部分を含む.
  • C.C++はあくまでCをベースにしています.これはプロセス向けの部分で、CはC++に比べてテンプレート、異常、リロードが少なくなっています.
  • Object-Oriented. カプセル化、継承、マルチステート、および虚関数バインドなど、オブジェクト向けのセクション.
  • Template C++. 汎用プログラミング部、template metaprogramming(TMP、テンプレートメタプログラミング)は、C++標準テンプレートライブラリSTLの各部分に基づいている.
  • STL. コンテナ、反復器、アルゴリズム、関数オブジェクトなどを含むC++標準テンプレートライブラリ.C++効率的なプログラミング規則は、この4つの部分のどの部分を使用しているかによって状況によって変化することを覚えておいてください.

  • 条項2.できるだけconst,enum,inlineで#defineの代わりに
    等価は、プリプロセッサの代わりにコンパイラを使用できることを示します.#defineすなわちマクロ定義は、前処理段階で処理され、通常は記号名が記号テーブル(symbol table)に入り、コンパイラ処理前にプリプロセッサに移動され、記号テーブルに入らない場合、コンパイルエラーになる可能性がある.解決策はマクロの代わりに定数を使用する.例:const double AspecRatio = 1.653;#define ASPEC_RATIO 1.653;の代わりに使用する2点に特に注意する.-ポインタ定数と定数ポインタ、特にconst stringconst char* constの代わりに使用する.-class排他定数:static constで修飾され、静的定数:たとえば、class GamePlayer{ static const int NumTurns = 5; // };または定数クラス内宣言+クラス外定義を使用する:class GamePlayer{static const int NumTurns;};//
    const int GamePlayer::NumTurns = 5;//
    マクロ定義を使用してclass排他定数を作成することはできません.マクロ定義は役割ドメインを重視していないためです.マクロ定義は単純な埋め込みであり、タイプチェックは行わないので、マクロを定義するときは、マクロのすべての実パラメータにカッコを付けてください.例:#define CALL_MAX(a, b) ((a) > (b) ? (a) : (b))呼び出し:
    int a = 5, b = 0;
    CALL_MAX(++a, b);   //a   1 
    CALL_MAX(++a, b + 10);  //a   2 

    これは予測不可能な動作であるため、マクロ定義関数の代わりにインライン関数を使用します.単純定数の場合はconstオブジェクトまたはenumを使用してdefinesを置き換えることが望ましいことを覚えておいてください.近似関数のマクロについては、definesをinline関数に置き換えることが望ましい.
    条項3.できるだけconstを使う
    constキーワードは、コンパイラの値が読み取り専用であることを示します.-定数ポインタとポインタ定数たとえばSTLの反復器.
    const vector<int>::iterator ite1;//       ,ite1    
    vector<int>::const_iterator ite2;//       ,*ite2    
  • constは、コンパイラが「==」を判断し、値を割り当てるなどのエラーを特定するのに役立ちます.
  • const Rational operator*(const Rational& lhs, const Rational& rhs);//        
    Rational a, b, c;
    if(a * b = c)...//            ,        ,    const  ,           。
  • constメンバー関数constメンバー関数thisポインタを表すタイプは、const className const*です.C++プログラムの効率を改善する根本的な方法は、constメンバー関数を使用してconstオブジェクトを処理する必要があることを前提として、pass by reference-to-constでオブジェクトを渡すことです.constメンバー関数の2つの流行概念:bitwise constness(physical constness):どのメンバー変数も読み取り専用である場合にconstと言える.(Object Model 2.2 Copy Constructorの構築操作では、bitwise copies)logical constness:1つのconstメンバー関数は、処理するオブジェクト内のいくつかのbitsを変更できますが、ポインタが指すオブジェクトを変更するなど、クライアントが検出できない場合にのみ可能です.non-staticメンバー関数のbitwise constness制約を解放する方法:mutableキーワードを使用すると、constメンバー関数でもmutable修飾メンバーが可変になります.
  • constとnon-consメンバー関数でnon-constバージョンを再利用してconstバージョンを呼び出すことを避け、さらにモデルチェンジconst_を加えるcast、static_cast、例えば:
  • const char& operator[](int pos) const;//const  
    char& operator[](int pos) { //non-const  
        return const_cast<char&> //     ,  const
         (static_cast<const className&>(*this)[pos]);//*this  ,  const
    }

    逆にconstバージョンを使用してnon-constバージョンを呼び出すのはエラーです.コンパイラがエラーを検出するのに役立つものがあることを覚えておいてください.constは、任意の役割ドメイン内のオブジェクト、関数パラメータ、関数戻りタイプ、メンバー関数自体に適用できます.コンパイラはbitwise constnessを強制的に実装しますが、プログラムを作成するときは「概念的な定数」(conceptual constness)を使用する必要があります.constとnon-constメンバー関数が実質的に等価に実装されている場合、non-constバージョンを使用してconstバージョンを呼び出すと、コードの重複を回避できます.
    条項4.オブジェクトが使用される前に初期化されていることを確認
    オブジェクトが使用される前に常に初期化します.組み込みタイプの場合は、手動で初期化してください.非組み込みタイプの場合、初期化のタスクはコンストラクション関数に落ちます.割り当てと初期化の概念を混同しないでください.たとえば、次のようにします.
    class ABEntry {
    public:
        ABEntry(const string& name, const string& address, int num) {
            //      ,     ,       default ctor,   
            _name = name;
            _address = address;
            _num = num; 
            }
    private:
        string _name;
        string _address;
        int _num;
    }

    より良い方法は、いわゆるメンバー初期値列(member initialization list)を使用することです.
    ABEntry::ABEntry(const string& name, const string& address, int num)
        : _name(name), _address(address), _num(num) { }
    //    copy ctor,        

    特に、欠落を避けるために、初期値列にすべてのメンバー変数をリストします.また、メンバー変数がconstまたはreferenceの場合、必ず初期値が必要で、値を割り当てることはできません.最も簡単な方法は、メンバーの初期値列を使用することです.C++は、宣言された順序で初期化され、ベースクラスが派生クラスより先に初期化される固定的な初期化順序を有する.
    class init {
    public:
            init(int i) : _j(i), _i(_j);
            //       ,    _i   ,  _j   。
    private:
        int _i;
        int _j;
    }

    local static object(ローカル静的オブジェクト)では、プログラムが終了すると、オブジェクトが自動的に破棄されます.ローカル静的オブジェクトに基づくsingleton設計モード:
    class Singleton
    {
    public:
        static Singleton& getInstance() {
            static Singleton s;
            return s;
        }
    private:
        Singleton() {}
        Singleton(const Singleton&);
        void operator=(const Singleton&);
    };

    組み込みタイプの手動初期化は、C++が初期化を保証しないことを覚えておいてください.コンストラクション関数は、メンバーの初期値列を使用することが望ましい.コンストラクション関数で付与操作を使用しないでください.初期値列のメンバー変数の順序は、宣言の順序と一致する必要があります.コンパイルユニット間の初期化順序の問題を回避するには、non-local staticオブジェクトの代わりにlocal staticオブジェクト参照を返す関数を使用します.
    侯捷先生の翻訳した《Effective C+》の中国語版の第3版を参考にします