CERT.OOP.CTOR.INIT_ORDER
コンストラクタメンバー初期化子は正規の順序で記述してください。
クラスコンストラクタのメンバー初期化子リストを使用すると、メンバーを指定した値に初期化し、基底クラスコンストラクタを特定の引数で呼び出すことができます。ただし、初期化が発生する順序は一定であり、メンバー初期化子リストに記述される順序に左右されることはありません。つまり、メンバー初期化子がメンバー初期化子リストに現れる順序は無関係です。
メンバーが初期化される順序 (基底クラスの初期化を含む) は、クラスメンバー変数の宣言順序または基底クラス指定子リストによって決まります。正規の順序以外でメンバー初期化子を記述すると、初期化されていないメモリの読み取りなど、定義されていない動作が発生する可能性があります。
脆弱性とリスク
正規の順序以外でメンバー初期化子を記述すると、初期化されていないメモリの読み取りなど、定義されていない動作が発生する可能性があります。
軽減と防止
メンバー初期化子を常に正規の順序でコンストラクタに記述してください (最初にクラスの基底指定子リストに現れる順序で直接基底クラスを記述し、次にクラス定義で宣言された順序で非静的データメンバーを記述する)。
例
コピー
class C_positive {
int dependsOnSomeVal;
int someVal;
public:
C_positive(int val) : someVal(val), dependsOnSomeVal(someVal + 1) {} // uncompliant code
};
class C_negative {
int someVal; // adjust the declarations order
int dependsOnSomeVal;
public:
C_negative(int val) : someVal(val), dependsOnSomeVal(someVal + 1) {} //compliant code
};
class B1 {
int val;
public:
B1(int val) : val(val) {}
};
class B2 {
int otherVal;
public:
B2(int otherVal) : otherVal(otherVal) {}
int get_other_val() const { return otherVal; }
};
class D_positive : B1, B2 {
public:
D_positive(int a) : B2(a), B1(get_other_val()) {} // uncompliant code
};
class B1 {
int val;
public:
B1(int val) : val(val) {}
};
class B2 {
int otherVal;
public:
B2(int otherVal) : otherVal(otherVal) {}
};
class D_negative : B1, B2 {
public:
D_negative(int a) : B1(a), B2(a) {} // compliant code
};