メインコンテンツ

AUTOSAR C++14 Rule A12-0-1

If a class declares a copy or move operation, or a destructor, either via "=default", "=delete", or via a user-provided declaration, then all others of these five special member functions shall be declared as well

説明

ルール定義

クラスで "=default"、"=delete"、またはユーザー指定の宣言を介してコピー操作、移動操作、またはデストラクターが宣言されている場合は、他の 5 つの特殊なメンバー関数もすべて宣言するものとします。

根拠

これらの特殊なメンバー関数は、コピー操作または移動操作で呼び出されます。

  • コピー コンストラクター

  • コピー代入演算子

  • 移動コンストラクター

  • 移動代入演算子

  • デストラクター

これらの関数のいずれかを明示的に宣言しなかった場合は、コンパイラがそれらを暗黙的に定義します。この暗黙的な定義は、オブジェクトのシャロー コピーを実装するため、エラーの原因になる可能性があります。特殊なメンバー関数の一部を明示的に宣言する必要がある場合は、そのすべてを宣言する必要があります。たとえば、動的に割り当てられたメモリへの生のポインターを含むオブジェクトをコピーするものとします。暗黙的なコピー コンストラクターが、元のポインターとコピー先のポインターが同じメモリを指すオブジェクトをシャロー コピーします。オブジェクトのいずれかが破棄されると、割り当てられたメモリが割り当て解除され、他のオブジェクト内に使われないポインターがそのまま残ることになります。使われないポインターにアクセスすると、セグメンテーション エラーが起きる可能性があります。特殊なメンバー関数は密接に関係しているため、他の関数の暗黙的な実装は同様のエラーにつながる可能性があります。動的に割り当てられたリソースのライフサイクルを管理するには、5 つすべての特殊なメンバー関数を明示的に宣言します (Rule of Five)。または、特殊なメンバー関数の暗黙的な定義でメモリ管理が正しく実装されたオブジェクトを使用し、それらの関数を明示的に宣言しないようにすることもできます (Rule of Zero)。

特殊なメンバー関数の全部ではなく一部を明示的に宣言することによって、コンパイラが宣言されていない特殊なメンバー関数を使用しないようにできます。たとえば、クラスのコピー コンストラクターまたはデストラクター関数のみを明示的に宣言した場合は、コンパイラが移動コンストラクターと移動代入演算子を暗黙的に定義しなくなります。クラスは、誤ってコピー専用クラスになる可能性があります。逆に、移動コンストラクターと移動代入演算子のみを明示的に宣言した場合は、コンパイラがコピー コンストラクターとコピー代入演算子を削除済みとして定義することによって無効にします。クラスは、意図しなかったかもしれませんが、移動のみのクラスになります。このような不必要な効果を回避するには、Rule of Five と Rule of Zero のどちらかに従います。

クラスのコンストラクターはこのルールに含まれません。

Polyspace 実装

Polyspace® は、5 つの特殊なメンバー関数の全部ではなく一部を明示的に宣言したクラスにフラグを設定します。移動コンストラクターと移動代入演算子は C++11 で導入されたことに注意してください。Polyspace は、古いコードに例外を認めません。

トラブルシューティング

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

すべて展開する

この例では、AUTOSAR rule A12-0-1 の Polyspace 実装を示します。

// Class rendered copy-only, perhaps inadvertently
class A               // Noncompliant.
{
    public:
      ~A()
      {
        // ...
      }

    private:
      // Member data ...
};


//Class rendered move-only, perhaps inadvertently
class B          // Noncompliant
{
   public:
		B(B&&) = default;
		B& operator=(B&&) = default; 
    private:
      // Member data ...
	
};
template<typename T>
class BaseT              // Compliant - rule of five.
{
  public:
    BaseT(BaseT const&) = delete;               
    BaseT(BaseT&&) = delete;                    
    virtual ~BaseT() = default;                 
    BaseT& operator=(BaseT const&) = delete;    
    BaseT& operator=(BaseT&&) = delete;         
    protected:
    BaseT() = default;   
};

template<typename T>
class SimpleT           // Compliant - rule of zero.
{
  public:
    SimpleT(T t): t_(t)
    {

    }

  private:
    T t_;
};

main()
{
	//..	
}

クラス A はそのデストラクターのみを宣言します。これは、コンパイラが移動コンストラクターと移動代入演算子を定義しなくなるため、このクラスがコピー専用になることを意味します。クラス B は移動コンストラクターと移動代入演算子を宣言します。これは、コンパイラがコピー コンストラクターとコピー代入演算子を無効にするため、このクラスが移動のみになることを意味します。これらの効果が意図的かどうかはわかりません。Polyspace は、これらの宣言にフラグを設定し、特殊なメンバー関数が不足していることを示します。クラス BaseT はこのルールに従っています。これは、5 つすべての特殊なメンバー関数が宣言されているためです。同様に、SimpleT もこのルールに従っています。これは、どの特殊なメンバー関数も宣言されておらず、それらの暗黙的な定義に依存しているためです。

チェック情報

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

バージョン履歴

R2020a で導入