メインコンテンツ

AUTOSAR C++14 Rule A20-8-6

std::make_shared shall be used to construct objects owned by std::shared_ptr

説明

ルール定義

std::make_shared shall be used to construct objects owned by std::shared_ptr.

根拠

関数 std::make_shared を使用することによって、直接 std::shared_ptr オブジェクトを作成します。

auto numberPtr = std::make_shared<numberClass>(aNumber);
生のポインターを動的メモリに変換して std::shared_ptr オブジェクトを作成することは避けます。
class numberClass {
   public:
     numberClass(int n): number(n){}
   private: 
     int number;
}
int aNumber=1; 
std::shared_ptr<numberClass> numberPtr (new numberClass(aNumber)); 

以下の理由で std::make_shared を使用することを推奨します。

  • std::shared_ptr オブジェクトの作成が単一の動的なメモリ割り当てで実行され、実行時パフォーマンスが向上します。そうしない場合、new 演算子を使用することにより生のポインターを作成することで 1 回の動的メモリ割り当てが必要になり、生のポインターを std::shared_ptr オブジェクトに変換することで 2 回目の割り当てが必要になります。2 回目の割り当てでは共有リソースの参照カウントを追跡するための制御ブロックが作成され、共有リソースへのすべてのポインターを認識する std::shared_ptr オブジェクトが作成されます。

  • std::make_shared を使用した std::shared_ptr オブジェクトの作成は例外セーフです。そうしない場合、new 演算子を使用する動的メモリ割り当てとそれに続く変換の間で例外が発生する可能性があり、そうするとメモリ リークを招きます。例外でメモリ リークが引き起こされるのは特定のコンテキストの場合のみです。たとえば、std::shared_ptr オブジェクトが複数パラメーター関数の引数で作成され、もう一方の関数引数評価で例外がスローされる場合です。

  • より簡潔な構文を使用できます。動的に割り当てられるオブジェクトのデータ型を繰り返す必要はありません。

Polyspace 実装

チェッカーは、new 演算子から返された生のポインターからの std::shared_ptr オブジェクト (または boost::shared_ptr オブジェクト) の作成にフラグを設定します。

トラブルシューティング

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

すべて展開する

#include<memory>
#include <cstdint>
#include <string>

class Record {
public:
	Record() = default;
	Record(std::string aName, std::string someInfo): name(aName), info(someInfo){       
	}
private:
	std::string name;
	std::string info;
};

void addRecordToDataBase(std::shared_ptr<Record> aRecord, bool dataBaseIsFull);
bool checkDataBase(void); //Checks if database can accept more entries

void createRecord() {
	std::shared_ptr<Record> recordPtr1 (new Record("John", "Mechanic, New York")); //Noncompliant
	auto recordPtr2 = std::make_shared<Record>("Tom", "Plumber, Boston"); //Compliant
	//...
	addRecordToDataBase(std::shared_ptr<Record>(new Record("John", "Mechanic, New York")), checkDataBase()); //Noncompliant
	addRecordToDataBase(std::make_shared<Record>("Tom", "Plumber, Boston"), checkDataBase()); //Compliant
	//...
}

std::shared_ptr<Record> getSP(void) {
	std::shared_ptr<Record> result{std::make_shared<Record>()};//Compliant 
	return result;                                                      
}

この例では、new 演算子が生のポインターを返し、それに続く変換によって生のポインターから std::shared_ptr オブジェクトが作成されるたびに、ルール違反になります。

addRecordToDatabase の最初の呼び出しでは、次のイベント シーケンスが発生する可能性があります (C++17 より前のバージョンの場合)。

  • 第 1 引数の評価。new 演算子によって Record オブジェクトのメモリが動的に割り当てられる。

  • 第 2 引数の評価。関数 checkDataBase が呼び出される。

  • 第 1 引数の評価の続き。new から取得された生のポインターが std::shared_ptr オブジェクトに変換される。

第 2 ステップで例外がスローされると、生のポインターはリソース管理オブジェクトに割り当てられず、その結果、メモリ リークが発生します。Polyspace は、最初の addRecordToDatabase 呼び出しにフラグを設定します。

関数 getSP() 内の共有ポインター result は、一時オブジェクト shared_ptr からコピーされて構築されます。return ステートメントでは、共有ポインターの暗黙的なコピーも行われます。Polyspace は、これらの演算にフラグを設定しません。

チェック情報

グループ: General utilities library
カテゴリ: Required、Automated

バージョン履歴

R2020b で導入

すべて展開する