メインコンテンツ

CERT C++: OOP54-CPP

Gracefully handle self-copy assignment

説明

ルール定義

自己コピー代入は適切に処理します。1

Polyspace 実装

ルール チェッカーは、"自己代入が演算子でテストされていません" をチェックします。

すべて展開する

問題

自己代入が演算子でテストされていませんは、オブジェクトのコピー代入演算子の引数が当のオブジェクトそのものであるかどうかテストされない場合に発生します。

リスク

自己代入は不必要なコピーの原因となります。オブジェクトがそれ自体に代入される可能性は低いものの、エイリアシングのため、ユーザー クラスのユーザーが自己代入を必ず検出できるわけではありません。

データ メンバーがポインターであり、そのポインターにメモリが動的に割り当てられる場合、自己代入は捉えにくいエラーの原因となることがあります。コピー代入演算子では通常、次の手順が実行されます。

  1. ポインターに元々関連付けられていたメモリの割り当てを解除する。

    delete ptr;
    
  2. ポインターに新たなメモリを割り当てる。新たなメモリ位置を、演算子の引数から取得した内容で初期化する。

     ptr = new ptrType(*(opArgument.ptr));
    

演算子の引数 opArgument がオブジェクト自体である場合、最初の手順が終了しても、演算子の引数にあるポインター データ メンバー opArgument.ptr はメモリの位置に関連付けられません。*opArgument.ptr に含まれる値は予測できないものになります。したがって、2 番目の手順では、予測不能な値で新たなメモリ位置が初期化されます。

修正方法

自己代入をユーザー クラスのコピー代入演算子でテストします。コピー代入演算子での代入は、テストが完了してから実行してください。

例 - 自己代入のテストがない
class MyClass1 { };
class MyClass2 {
public:
    MyClass2()                : p_(new MyClass1())      { }
    MyClass2(const MyClass2& f)   : p_(new MyClass1(*f.p_)) { }
    ~MyClass2()                {
        delete p_;
    }
    MyClass2& operator= (const MyClass2& f) //Noncompliant
    {
        delete p_;
        p_ = new MyClass1(*f.p_);
        return *this;
    }
private:
    MyClass1* p_;
};

この例では、MyClass2 のコピー代入演算子で自己代入がテストされません。パラメーター f が現在のオブジェクトである場合、ステートメント delete p_ の後に、ポインター f.p_ に割り当てられていたメモリも割り当てを解除されます。したがって、ステートメント p_ = new MyClass1(*f.p_) は、p_ が指すメモリ位置を予想不能の値で初期化します。

修正 — 自己代入のテスト

1 つの修正方法として、コピー代入演算子で自己代入をテストします。

class MyClass1 { };
class MyClass2 {
public:
    MyClass2()                : p_(new MyClass1())      { }
    MyClass2(const MyClass2& f)   : p_(new MyClass1(*f.p_)) { }
    ~MyClass2()                {
        delete p_;
    }
    MyClass2& operator= (const MyClass2& f)
    {
        if(&f != this) {
           delete p_;
           p_ = new MyClass1(*f.p_);
        }
        return *this;
    }
private:
    MyClass1* p_;
};

チェック情報

グループ: 09.オブジェクト指向プログラミング (OOP)

バージョン履歴

R2019a で導入


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.