メインコンテンツ

AUTOSAR C++14 Rule A12-1-1

Constructors shall explicitly initialize all virtual base classes, all direct non-virtual base classes and all non-static data members

説明

ルール定義

コンストラクターは、すべてのバーチャル基底クラス、すべての直接非バーチャル基底クラス、およびすべての非静的データ メンバーを明示的に初期化するものとします。

根拠

派生クラスがその基底クラスのコンストラクターを明示的に初期化しなければ、コンパイラにより、基底クラスが暗黙的に初期化されます。その場合、無効な状態のオブジェクトまたは意図しない初期値をもつオブジェクトが構築される可能性があり、実行時に予期せぬコードの動作が生じるリスクがあります。次のダイヤモンド クラス階層を考えてください。この階層では、基底クラス Parent に複数のコンストラクターがあります。

class Parent{
	public:
	Parent(){/*...*/}
	Parent(int i){/*...*/}
};

class Child1: public virtual Parent{
	public:
	Child1(): Parent(2){/*...*/}
};

class Child2: public virtual Parent{
	public:
	Child2(): Parent(1){/*...*/}
	
};

class GrandChild: public Child1, public Child2{
	public:
	GrandChild(){/*...*/}
}
GrandChild オブジェクトを構築するときに、1 または 2 のどちらを引数として使用してParent が構築されるのかが明白ではありません。Parent の初期化に使用するコンストラクターを GrandChild で明示的に指定すると、このあいまいさが解決されます。無効な状態または意図しない初期値を回避するには、派生クラス コンストラクターの初期化リスト内で必要な基底クラス コンストラクターを直接呼び出します。

Polyspace 実装

Polyspace® は、派生クラス コンストラクターの初期化リストが次のようになっている場合、コンストラクターにフラグを設定します。

  • バーチャル基底クラスのコンストラクターを明示的に呼び出していない。

  • 直接非バーチャル基底クラスのコンストラクターを明示的に呼び出していない。

  • 非静的データ メンバーを明示的に初期化していない。

非静的データ メンバーが、分岐、ループ、または例外処理ステートメントの 1 つ以上のブランチで初期化される場合、Polyspace はそのデータ メンバーが初期化されると見なします。

Polyspace は、デリゲート コンストラクターが使用されている場合にこのルールに対する違反を報告しません。

トラブルシューティング

ルール違反が想定されるものの、Polyspace から報告されない場合は、コーディング規約違反が想定どおりに表示されない理由の診断を参照してください。

すべて展開する

#include <cstdint>    

class A {  
public:  
	A() : a{1} {}  
	virtual void abstractA() const = 0;  
private:  
	int a;  
};  

class B : public  A {  
public:  
	B() : b{1} {} //Noncompliant 
	void abstractA() const override {}  
private:  
	int b;  
};  

class C {  
public:  
	C() : c{3} {}  
private:  
	int c;  
};  

class D : public B, public C {  
public:  
	D() : B(), C(), e{5} {} //Compliant 
private:  
	int e;  
};  

int main() {   
	D dName;  
	return 0;   
} 

この例では、基底クラスと非静的データ メンバーがクラス コンストラクターによって明示的に初期化されていないため、Polyspace はこのコンストラクターにフラグを設定します。次に例を示します。

  • B クラスのコンストラクターは基底クラス A を明示的に初期化していないため、このルールに準拠していません。この問題を解決するには、B コンストラクターの初期化リスト内で A クラスのコンストラクターを呼び出します。

  • D クラスのコンストラクターは、初期化リスト コンストラクターの呼び出しによって、直接非バーチャル基底クラスの両方を明示的に初期化しているため、ルールに準拠しています。

#include <cstdint>   
class A { 
public: 
	A() : a{1} {} 
	virtual void abstractA() const = 0; 
private: 
	int a; 
}; 


class B : public virtual A { 
public: 
	B() : A(), b{1} {} //Compliant 
	void abstractA() const override {} 
private: 
	int b; 

}; 


class C : public virtual A { 
public: 
	C() : c{3} {} //Noncompliant 
	void abstractA() const override {} 
private: 
	int c; 
}; 


class D : public B, public C { 
public: 

	D() : B(), C(), e{5} {} //Noncompliant 
private: 
	int e; 
}; 



int main() {  
	D dName; 
	return 0;  
} 

この例では、基底クラスと非静的データ メンバーがクラス コンストラクターによって明示的に初期化されていないため、Polyspace はこのコンストラクターにフラグを設定します。次に例を示します。

  • B クラスのコンストラクターはその直接基底クラスを初期化リスト内で明示的に初期化しているため、ルールに準拠しています。

  • C クラスのコンストラクターはその直接基底クラス A を明示的に呼び出していないため、ルールに準拠していません。この問題を解決するには、C コンストラクターの初期化リスト内で A クラスのコンストラクターを呼び出します。

  • D クラスのコンストラクターはそのバーチャル基底クラス A を明示的に呼び出していないため、ルールに準拠していません。複数のバーチャル継承であることから、最上位の派生クラスがバーチャル基底クラスを初期化する必要があります。この問題を解決するには、D コンストラクターの初期化リスト内で A クラスのコンストラクターを呼び出します。

C++11 以降では、クラスに複数のコンストラクターが含まれている場合に、デリゲート コンストラクターを使用することによって、クラス設計を簡略化できます。デリゲート コンストラクターを使用する場合は、各コンストラクター内のすべてのデータ メンバーと基底クラスを初期化する必要がありません。この例では、Polyspace は、コンストラクター Derived::Derived(int) がその初期化義務を Derived::Derived(int, int) にデリゲートした場合に、このルールの違反を報告しません。

class Base {
public:
	Base() : a{1} {}                    

	virtual void abstractA() const = 0;

private:
	int a;
};
class Derived: public Base {
public:
	Derived(int a, int b): Base{}, z{a}, y{b} {}  //Compliant
	Derived(int a): Derived(a, 0) {}  //Compliant

private:
	int z;
	int y;
};

チェック情報

グループ: 特殊なメンバー関数
カテゴリ: Required、Automated

バージョン履歴

R2019a で導入

すべて展開する