メインコンテンツ

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

MISRA C++:2023 Rule 23.11.1

The raw pointer constructors of std::shared_ptr and std::unique_ptr should not be used

R2024b 以降

説明

ルール定義

The raw pointer constructors of std::shared_ptr and std::unique_ptr should not be used. 1

根拠

new 演算子の使用と、その結果得られる生のポインターを std::unique_ptr または std::shared_ptr オブジェクトに変換することとによってメモリを割り当てる代わりに、たとえば以下のようにします。

class numberClass {
   public:
     numberClass(int n): number(n){}
   private: 
     int number;
}
int aNumber=1; 
std::unique_ptr<numberClass> numberUniquePtr (new numberClass(aNumber));
std::shared_ptr<numberClass> numberSharedPtr (new numberClass(aNumber));
std::make_unique または std::make_shared 関数を使用して、直接 std::unique_ptr または std::shared_ptr オブジェクトを作成します。次に例を示します。
auto numberUniquePtr = std::make_unique<numberClass>(aNumber);
auto numberSharedPtr = std::make_shared<numberClass>(aNumber);

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

  • std::make_unique を使用した std::unique_ptr オブジェクトの作成、または std::make_shared を使用した std::shared_ptr オブジェクトの作成は例外セーフで、実行時のパフォーマンスを向上させます。たとえば、new 演算子を使用する動的メモリ割り当てとそれに続く変換がそれぞれ異なるステップで行われると、ステップの間で、メモリ リークの発生につながる例外が発生する可能性があります。

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

Polyspace 実装

チェッカーは以下にフラグを設定します。

  • new 演算子から返された生のポインターからの std::unique_ptr オブジェクト (または boost::unique_ptr オブジェクト) の作成。

  • new 演算子から返された生のポインターからの std::shared_ptr オブジェクト (または boost::shared_ptr オブジェクト) の作成。

トラブルシューティング

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

すべて展開する

#include <cstdint>
#include <string>

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

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

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

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

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

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

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

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

第 2 ステップで例外がスローされると、生のポインターはリソース管理オブジェクトに割り当てられず、その結果メモリ リークが発生します。

#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
カテゴリ: 推奨

バージョン履歴

R2024b で導入


1 All MISRA coding rules and directives are © Copyright The MISRA Consortium Limited 2021.

The MISRA coding standards referenced in the Polyspace Bug Finder™ documentation are from the following MISRA standards:

  • MISRA C:2004

  • MISRA C:2012

  • MISRA C:2023

  • MISRA C++:2008

  • MISRA C++:2023

MISRA and MISRA C are registered trademarks of The MISRA Consortium Limited 2021.