比較バージョン

キー

  • この行は追加されました。
  • この行は削除されました。
  • 書式設定が変更されました。

...

コンストラクタには、お作法があります。以下は鉄則として考えておきましょう。

  1. primitive は明示的に初期化する
    スタックオブジェクトでは(2013-12-18 21:32 訂正、newでも同様と指摘を頂きました)
    int 等の primitive 型のメンバーは初期化されません。
    明示的に初期化をしないと、思わぬ事故につながるので、必ず初期化しましょう。

    コード ブロック
    cpp
    cpp
    struct C {
        C() {}                  // i は 0 初期化されない!
        int i;
    };
    
    int f() {
        C c;
        return c.i;             // 不定
    }
    
  2. 初期化子で必ず全メンバーを初期化する
    初期化はコンストラクタのボディでいいと思っていませんか?
    初期化子をかかなくても、じつはデフォルトコンストラクタでメンバーは初期化されています。
    また、const や参照メンバーは初期化子でなければ初期化できません。必ず初期化子で全メンバーを初期化しましょう。

    コード ブロック
    cpp
    cpp
    class C {
    public:
        C(const std::string& s) {
            m_name = s;              // 初期化でなく代入。もし m_name が const ならコンパイルできない。
            m_i = 0;                 // コンパイルエラー
        }
        C(const std::string& s):
            m_name(s), m_i(0) {}     // good
    private:
        std::string m_name;
        const int m_i;
    };
    
  3. 初期化子の記述順序は、メンバーの定義順にする
    実は初期化子の記述順序は、初期化の順序と無関係です。メンバーは、メンバーが定義された順に初期化されます。
    なので、メンバーの定義順と異なる初期化子の記述順序はバグのもとになります。

    コード ブロック
    cpp
    cpp
    class C {
    public:
        C( std::size_t size):
            m_buf(size),
            m_top(&(m_buf[0])),
            m_bottom(m_top + size) {}   // m_bottom の定義が先なので、m_top 初期化前にこちらが実行される
    private:
        std::vector<char> m_buf;
        char* const m_bottom;
        char* const m_top;
    };
    
  4. コンストラクタのボディは原則として空
    整合性のチェックなどをのぞき、複雑なロジックを避けるべきです。なぜかというと、C++ は Java と違ってオーバーロードされた他のコンストラクタに初期化処理を委譲できないため、複数のコンストラクタで同じ処理を書くことになりがちだからです(後述する C++11 では可能になります)。

...