メインコンテンツ

AUTOSAR C++14 Rule A12-8-4

Move constructor shall not initialize its class members and base classes using copy semantics

説明

Move constructor shall not initialize its class members and base classes using copy semantics.

根拠

C++ では、移動演算はソース オブジェクトからターゲット オブジェクトにリソースそのものを複製するのではなく、リソースの所有権を移譲します。移動コンストラクターはリソースを複製しないため、コピー コンストラクターより高速です。CopyTarget オブジェクトがコピー構築され、MoveTarget オブジェクトが Source オブジェクトから移動構築される次のコードについて考えます。

class BigData{
	//...
	BigData(BigData&&){  //Move Constructor
		//...
	} copy constructed
	BigData(const BigData&){  //Copy Constructor
		//...
	}
private:
	std::map<int, std::string> BigBook;
};

int main(){
	BigData Source;
	BigData CopyTarget = Source;
	BigData Movetarget = std::move(Source);
	//...
}

CopyTarget をコピー構築する場合は、コンパイラが Source から CopyTarget にリソース Source::BigBook を複製します。コピー構築後は、これらの両方のオブジェクトにリソース BigBook のコピーが追加されます。Movetarget を移動構築する場合は、コンパイラがリソース Source::BigBook の所有権を MoveTarget に移譲します。移動構築は物理的にリソースを複製しないため、コピー構築より高速です。

移動構築は最適化戦略です。移動構築はコピー構築より低コストで高速であると想定します。データ メンバーと基底クラスのコピー初期化は、移動コンストラクターを低速で非効率にして、プログラムのパフォーマンスを低下させる可能性があります。開発者は、移動構築では移動セマンティクスのみが使用されると想定します。想定に反して、移動コンストラクターでコピーのセマンティクスを使用すると、リソース リークや将来の開発での矛盾が発生する可能性があります。移動コンストラクターを作成するときに、移動セマンティクスを使用してデータ メンバーと基底クラスを初期化します。このルールに違反することなく、スカラー データ メンバーをコピー初期化できます。

std::move() を使用して、コード内に移動セマンティクスを実装することもできます。std::move() を使用してオブジェクトを移動する場合は、修飾子 const を使用せずにオブジェクトまたはデータ メンバーを宣言します。詳細については、AUTOSAR C++14 Rule A18-9-3を参照してください。

Polyspace 実装

移動コンストラクターが移動セマンティクスを使用して非スカラー データ メンバーと基底クラスを初期化しない場合は、Polyspace® がその宣言にフラグを設定します。たとえば、移動コンストラクターが移動コンストラクターではなく既定のコンストラクターを使用して基底クラスを初期化する場合は、Polyspace がその移動コンストラクターの宣言にフラグを設定します。

トラブルシューティング

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

すべて展開する

この例では、Polyspace がコピー初期化と既定の構築を使用する移動コンストラクターにどのようにフラグを設定するかを示します。

#include<cstdint>
#include<string>
#include<map>
#include <vector>
class BigData{
public:
	BigData()=default;
	//...
	BigData(BigData&& oth): //Compliant
	BigBook(std::move(oth.BigBook)),  
	Length(oth.Length)	
	{  
		//...
	} 
	
private:
	std::map<int, std::string> BigBook;
	int Length;
};

class slowBigData{
	//...
	slowBigData(slowBigData&& oth): //Noncompliant
	BigBook(oth.BigBook),  
	Length(oth.Length)	           
	{  
		//...
	} 
	
private:
	std::map<int, std::string> BigBook;
	int Length;
};

class BigData2: public BigData{
	//...
	BigData2(BigData2&& oth):BigData() //Noncompliant
	
	{  
		BigVector = std::move(oth.BigVector);
		//...
	} 
	
private:
	std::map<int, std::string> BigBook;
	std::vector<int> BigVector;
	int Length;
};

class BigData3: public BigData{
	//...
	BigData3(BigData3&& oth):BigData(std::move(oth)) //Compliant
	
	{  
		str = std::move(oth.str);
		//...
	} 
	
private:
	std::map<int, std::string> BigBook;
	int Length;
	std::string str;
};

  • クラス BigData の移動コンストラクターは、移動セマンティクスを使用してデータ メンバーBigBook を初期化します。移動コンストラクターは、コピーのセマンティクスを使用してスカラー メンバー Length を初期化します。スカラー データ メンバーのコピーはこのルールに違反しないため、この移動コンストラクターは準拠しています。

  • クラス slowBigdata の移動コンストラクターは、コピーのセマンティクスを使用してデータ メンバーを初期化します。この移動コンストラクターはルールに違反しており、Polyspace は、この移動コンストラクターの宣言にフラグを設定します。

  • クラス BigData2 の移動コンストラクターは、基底クラスの既定のコンストラクターを呼び出すため、コードが低速で非効率になる可能性があります。Polyspace は、この移動コンストラクターの宣言にフラグを設定します。クラス BigData3 の移動コンストラクターは、基底クラスの移動コンストラクターを呼び出します。この移動コンストラクターはこのルールに準拠しています。

チェック情報

グループ: 特殊なメンバー関数
カテゴリ: Required、Automated
PQL 名: std.autosar_cpp14.A12_8_4

バージョン履歴

R2020b で導入