メインコンテンツ

AUTOSAR C++14 Rule A12-8-6

Copy and move constructors and copy assignment and move assignment operators shall be declared protected or defined "=delete" in base class

説明

ルール定義

コピー コンストラクター、移動コンストラクター、コピー代入演算子、および移動代入演算子は、基底クラスで protected と宣言するか、"=delete" と定義するものとします。

根拠

派生クラスへのポインターは、基底クラスへのポインターと型互換性があります。ポインターは、派生クラスのオブジェクトを指しながら、基底クラスのオブジェクトにすることができます。このようなオブジェクトがコピーされると、基底コピー コンストラクターが呼び出され、コピーされたオブジェクトは元のオブジェクトの基底部分だけになります。コピーおよび移動時に誤ってスライスが行われないようにするために、次の方法で基底クラスでのこのような操作を抑制します。

  • コピー コンストラクター、移動コンストラクター、コピー代入演算子、および移動代入演算子を protected として宣言する。

  • コピー コンストラクター、移動コンストラクター、コピー代入演算子、および移動代入演算子を =delete として定義する。

Polyspace 実装

Polyspace® は、基底クラスの以下の特殊なメンバー関数が protected として宣言されていないか、=delete として定義されていない場合にフラグを設定します。

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

  • 移動コンストラクター

  • コピー代入演算子

  • 移動代入演算子

Polyspace は、このルールに反する特殊なメンバー関数を示します。

トラブルシューティング

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

すべて展開する

#include <cstdint>
#include <memory>
#include <utility>
#include <vector>
class A 
{                                           
  public:                                   
    int base_var;
    A() = default;                          
    A(A const&) = default;                //Noncompliant
    A(A&&) = default;                     //Noncompliant
    virtual ~A() = 0;                       
    A& operator=(A const&) = default;     //Noncompliant
    A& operator=(A&&) = default;          //Noncompliant
};                                          
class B : public A                          
{                                           
    int derived_var;
};                                          
class C //               
{                                           
  public:                                   
    int base_var;
    C() = default;                          
    virtual ~C() = 0;                       
                                            
  protected:                                
    C(C const&) = default;                //Compliant
    C(C&&) = default;                     //Compliant
    C& operator=(C const&) = default;     //Compliant
    C& operator=(C&&) = default;          //Compliant
};                                          
class D : public C                          
{
    int derived_var;
};
class E            
{                                            
  public:                                    
    int base_var;
    E() = default;                           
    virtual ~E() = default;                  
    E(E const&) = delete;                   //Compliant
    E(E&&) = delete;                        //Compliant
    E& operator=(E const&) = delete;        //Compliant
    E& operator=(E&&) = delete;             //Compliant
};

class F : public E                          
{
    int derived_var;
};
void Fn1() noexcept
{
  B obj1;
  B obj2;
  A* ptr1 = &obj1;
  A* ptr2 = &obj2;
  *ptr1 = *ptr2;             // Partial assignment only
  *ptr1 = std::move(*ptr2); // Partial move only
  D obj3;
  D obj4;
  C* ptr3 = &obj3;
  C* ptr4 = &obj4;
  // *ptr3 = *ptr4; // Compilation error 
  // *ptr3 = std::move(*ptr4); // Compilation error 
  F obj5;
  F obj6;
  E* ptr5 = &obj5;
  E* ptr6 = &obj6;
  // *ptr5 = *ptr6; // Compilation error 
  // *ptr5 = std::move(*ptr6); // Compilation error 
}

クラス A は、既定のコピー コンストラクター、既定の移動コンストラクター、既定のコピー代入演算子、および既定の移動代入演算子をもつ基底クラスです。クラス B は、A から派生し、A には存在しない変数 derived_var をもっています。Fn1() では、ptr1ptr2 の 2 つのポインターが作成されます。これらは、基底クラス A のオブジェクトですが、派生クラス B のオブジェクトである obj1obj2 をそれぞれ指します。代入 A *ptr = &obj1; は、基底クラスのポインターを宣言し、それに任意の派生クラスのオブジェクトを代入可能なポリモーフィックな動作の例です。

ptr1ptr2 は基底クラス A のオブジェクトであるため、*ptr1 = *ptr2 内のコピー操作によってクラス Adefault コピー代入演算子が呼び出されます。default セマンティクスは、obj2 の基底部分のみを obj1 にコピーします。つまり、obj2.derived_varobj1.derived_var にコピーされません。同様に、obj2.derived_var の所有権は、*ptr1 = std::move(*ptr2) 内の移動操作によって、obj1 に移動されません。誤ったスライスを回避するには、クラス階層の基底クラスでのコピー操作と移動操作を抑制します。Polyspace は、基底クラス A 内のコピー関数と移動関数にフラグを設定します。これは、これらの関数が protected として宣言されておらず、さらに =delete として定義されていないためです。

クラス C では、コピー コンストラクター、移動コンストラクター、コピー代入演算子、および移動代入演算子を protected として宣言することによってコピー関数と移動関数が抑制されます。クラス E では、これらの特殊なメンバー関数を =delete として宣言することによってコピー操作と移動操作が抑制されます。これらの基底クラスのコピー操作または移動操作を呼び出すと、コンパイラがエラーを生成します。基底クラスの CE の定義はこのルールに従っています。

チェック情報

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

バージョン履歴

R2020a で導入