4

オブジェクトをそれ自体の中で交換しようとしています。動作しますが、デストラクタを追加すると、ダブルフリーエラーが発生します。これを防ぐ方法はありますか?私が話している方法はですvoid swap(SimpleArray &object)

(私の投稿に間違った情報が含まれる前にこれを読んだ場合は申し訳ありません...)

#include "TestType.h"
class SimpleArray {

    private: 
        TestType* pArray;
        //TestType* temp;
    public:
        SimpleArray(TestType *array)
        {
            this->pArray = array;
        }
        ~SimpleArray() { delete[] pArray; }
        SimpleArray() { pArray = 0;}
        SimpleArray(const SimpleArray& arg){ pArray = arg.pArray; }
        ~SimpleArray() { delete[] pArray; }
        TestType * get() const{ return pArray; }
        bool isNonNull() const { return pArray != 0; }
        //TestType* pArray;
        void reset(TestType*& p) {this->pArray = p; }
        void reset() { pArray = 0; }

        void swap(SimpleArray &object) { SimpleArray temp; temp = object; object = *this; *this = temp;}
        TestType * release() { pArray = 0; return pArray; }
        TestType& getReference(int a) { return *pArray; }


};

これは機能しますが、デストラクタを追加すると、「ダブルフリーまたは破損エラー」が発生します。どうすればこれを解決できますか?これがメインの関数で、めちゃくちゃになっています。

bool testGetReleaseSwap() {
    SimpleArray array1;
    if (array1.get() != 0)
        return false;

    TestType* directArray1 = new TestType[100];
    array1.reset(directArray1);
    if (array1.get() != directArray1)
        return false;

    TestType* directArray2 = new TestType[50];
    SimpleArray array2(directArray2);

    array1.swap(array2);
    if (array1.get() != directArray2 || array2.get() != directArray1)
        return false;

    array2.swap(array1);
    if (array1.get() != directArray1 || array2.get() != directArray2)
        return false;

    array1.swap(array1);
    if (array1.get() != directArray1)
        return false;

    if (array1.release() != directArray1 || array2.release() != directArray2)
        return false;

    if (array1.get() != 0 || array2.get() != 0)
        return false;

    delete[] directArray1;
    delete[] directArray2;

    return true;
}
4

2 に答える 2

6

ここでの簡単な方法は、メソッドが二重削除を防ぐtemp.release()場合、最後に呼び出すことです。swap

ただし、根本的な問題ははるかに深いものです。C ++では、削除が必要なメモリ領域など、誰かが何かを所有しているという厳密なセマンティクスを常に維持することが重要です。

よくあるパターンは、何かを割り当てるオブジェクトがクリーンアップの責任を負い、他の誰も責任を負わないというものです。これはとうまく適合しSimpleArrayますが、コピーコンストラクターは所有者の数を増やすため、それを壊します!

共有データセマンティクスを実装するには、より多くの作業(参照カウントなど)を投資するか、配列のコピーを禁止してコピーコンストラクターをプライベートにする必要があります。

swapオブジェクトをコピーせずに動作するように修正するクリーンな方法は次のとおりです。

 void swap(SimpleArray &object) { 
    TestType* temp = object.pArray;
    object.pArray = this->pArray;
    this->pArray = temp;
 }

std::swap(object.pArray, pArray);同様に機能します)

配列のメモリ領域を交換することは、単一所有者のパターンにうまく適合するため、ここで問題となったのは、完全なオブジェクトコピーの使用のみです。

C++でのリソース管理と所有権のセマンティクスについて読む必要があります。誰が何を所有しているのかを完全に理解していない限り、コードは常にエラーが発生しやすくなります。

于 2012-08-26T23:55:14.390 に答える
2

浅いコピーセマンティクス(および場合によってはコピーオンライト)を持つクラスを実装しようとしているように思われます。これを正常に行うには、共有データの他の所有者がまだ何人いるかを追跡し、その数がゼロに達したときに所有オブジェクトを破棄する必要があります。そのためにを使用するか、std::shared_ptr自分でカウントする参照を実装することができます。

その特定の例の実際の問題については、コピーコンストラクターが実行していることを確認してください。コピーではなく、引数によってすでに所有されているオブジェクトへの別の参照(具体的にはポインタ)を取得するだけです。それ自体はすでにダブルフリーを取得するのに十分であり、swapテストケースは単にその問題を明らかにしています。

于 2012-08-27T00:05:24.030 に答える