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
 };