メインコンテンツ

AUTOSAR C++14 Rule A18-5-2

Non-placement new or delete expressions shall not be used

説明

ルール定義

Non-placement new or delete expressions shall not be used.

根拠

非配置の new または delete 演算子を明示的に使用すると、予期しない例外や戻り値によってメモリ リークが発生する可能性があります。new を明示的に呼び出してポインター用のメモリを割り当ててから、delete を明示的に呼び出してメモリの割り当てを解除する次のコードを考えてみましょう。

std::int32_t ThrowError(){
	std::int32_t errorCode;
	std::int31_t* ptr = new std::int32_t{0};
	//...
	if(errorCode!=0){
		throw std::runtime_error{"Error"};
	}
	//...
	if (errorCode != -1) {
		return 1;  
	}
	delete ptr;  
	return errorCode;
}
このコードは特定の条件下で予期しないメモリ リークにつながる可能性があります。

  • 1 つ目の if() ステートメントが true の場合は、関数が例外を生成し、ポインターを削除せずに終了します。

  • 2 つ目の if() ステートメントが true の場合は、関数が 1 を返し、ポインターを削除せずに終了します。

予測不能なメモリ リークを回避するには、非配置の new および delete 演算子を使用しないでください。代わりに、オブジェクトで動的に割り当てられたリソースをカプセル化してください。オブジェクト コンストラクターでリソースを取得し、オブジェクト デストラクターでリソースを解放します。この設計パターンは、"Resource Acquisition Is Initialization" (RAII) と呼ばれています。RAII パターンに従うことによって、予期せぬ例外や戻り値が発生した場合でも、メモリ リークが回避されます。

または、動的に割り当てられたリソースのライフタイムを管理するマネージャー オブジェクトを使用します。標準ライブラリのマネージャー オブジェクトの例を以下に示します。

  • std::unique_ptrstd::make_unique

  • std::shared_ptrstd::make_shared

  • std::string

  • std::vector

このルールは、ユーザー定義の RAII クラスおよびマネージャー内の new 演算子または delete 演算子には適用されません。

Polyspace 実装

AUTOSAR C++14 では、割り当てられたリソースがすぐに以下に渡される 2 つのケースで new 演算子を呼び出すことによる明示的なリソース割り当てが許可されます。

  • マネージャー オブジェクト

  • new 演算子の安全な代替手段がない RAII クラス

Polyspace® は、new 演算子と delete 演算子のすべての明示的な使用にフラグを設定します。new 演算子を容認可能なプロセスがあり、安全な代替手段がない場合は、結果またはコード内でコメントを使用して問題を正当化します。詳細は、以下を参照してください。

トラブルシューティング

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

すべて展開する

このコードは、Polyspace が new 演算子または delete 演算子にどのようにフラグを設定するかを示します。

#include <cstdint>
#include <memory>
#include <vector>
#include <cstddef>

using namespace std;

int32_t Fn1()
{
	int32_t errorCode{0};
	int32_t* ptr =
	new int32_t{0}; //Noncompliant
	// ...
	if (errorCode != 0) {
		throw  runtime_error{"Error"}; // Possible Memory Leak
	}
	// ...
	if (errorCode != 0) {
		return 1; //Possible Memory Leak
	}
	// ...
	delete ptr; //Noncompliant

	return errorCode; // Possible Memory Leak
}

int32_t Fn2()
{
	int32_t errorCode{0};
	// Alternative to 'new'
	unique_ptr<int32_t> ptr1 = make_unique< int32_t>(0); 
	unique_ptr<int32_t> ptr2(new  int32_t{0});   // Noncompliant
	shared_ptr<int32_t> ptr3 =
	make_shared<int32_t>(0);   //Compliant
	vector<int32_t> array;   // Compliant

	if (errorCode != 0) {
		throw  runtime_error{"Error"};   // No memory leaks
	}
	// ...
	if (errorCode != 0) {
		return 1; // No memory leaks
	}
	// ...
	return errorCode; // No memory leaks
}


class X
{
public:
	static void* operator new( size_t s)
	{
		return ::operator new(s);   // Noncompliant
	}

	static void* operator new[]( size_t s)
	{
		return ::operator new(s);   // Noncompliant
	}

	static void operator delete(void* ptr,  size_t s)
	{
		::operator delete(ptr);   // Noncompliant
	}

	static void operator delete[](void* ptr,  size_t s)
	{
		::operator delete(ptr);   // Noncompliant
	}
};

main(){
	X* x1    = new X;   // Noncompliant
	X* x2    = new X[2];   // Noncompliant
}

Fn1() では、演算子の newdelete がリソース管理で明示的に呼び出されます。その結果、予期せぬ例外や戻り値がメモリ リークにつながる可能性があります。Polyspace は、new 演算子と delete 演算子にフラグを設定します。Fn2() では、マネージャー オブジェクトがメモリ管理に使用されます。予期せぬ例外や戻り値のケースでも、Fn2() ではメモリ リークが発生しません。

クラス X には new 演算子と delete 演算子のカスタム オーバーロードが含まれています。Polyspace は、カスタム オーバーロードの定義内の new 演算子と delete 演算子のすべてのインスタンスにフラグを設定します。main() では、Polyspace がオーバーロードされた new 演算子と delete 演算子にもフラグを設定します。

チェック情報

グループ: 言語サポート ライブラリ
カテゴリ: Required、Partially automated

バージョン履歴

R2020a で導入