メインコンテンツ

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

自己代入が演算子でテストされていません

コピー代入演算子で自己代入がテストされない

説明

この欠陥は、オブジェクトのコピー代入演算子の引数がオブジェクト自体かどうかをテストしなかった場合に発生します。Polyspace® は、copy-and-swap イディオムを使用してコピー演算子を実装している場合に、この欠陥を報告しません。

リスク

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

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

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

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

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

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

修正方法

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

すべて展開する

#include <algorithm>

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)
	{
		delete p_;
		p_ = new MyClass1(*f.p_);
		return *this;
	}
private:
	MyClass1* p_;
};

class MyClass3 {
public:
	MyClass3& operator=( MyClass3& other) {
		MyClass3 tmp(other);
		swap(tmp);
		return *this;
	}

	void swap(MyClass3& other) noexcept{
		std::swap(obj_, other.obj_);
	}

	
private:
	
	MyClass1* obj_;
};

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

クラス MyClass3 は、copy-and-swap イディオムを使用してコピー代入演算子を実装します。パラメーター other が現在のオブジェクトである場合、この演算子では、コピー コンストラクターを使用して現在のオブジェクトの一時コピーを作成します。その後、オブジェクト tmp.obj_this.obj_ がスワップされてから、this ポインターが返されます。このコピー代入演算子は一時オブジェクトを作成することで、MyClass2::operator= での予期しない動作を防ぎます。Polyspace は、このコピー代入演算子にはフラグを設定しません。

修正 — 自己代入のテスト

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_;
};

結果情報

グループ: オブジェクト指向
言語: C++
既定値: 手書きコードはオン、生成コードはオフ
コマンド ライン構文: MISSING_SELF_ASSIGN_TEST
影響度: Medium

バージョン履歴

R2015b で導入

すべて展開する