2

演習として、手動ポインターを使用して、サイズ変更可能な配列クラス (std::vector) を作成しています (スマート ポインターの使用を開始する前に、それらがどのように機能するかを知りたいため)。ただし、Valgrind は checkMax() 関数でメモリ リークを報告します。

template <typename T>
class Array{
 public:
 Array() : len(0),maxLen(1){
    array=new T[maxLen];
    // ........ 
}
Array(unsigned length, T&content=0) : len(length),maxLen(length*2){
    array=new T[maxLen];
    //..............
}
~Array(){
    //delete[] array;
}
//..............
void push_back(const T& content){
    checkMax();
// do stuff...
}
private:
T* array;
unsigned int len;
unsigned int maxLen;
..
void checkMax(){
    if(len==maxLen){
    //allocate more memory for the array
        maxLen*=2;
        T*temp=new T[maxLen]; // ------------- MEMORY LEAK HERE -------------
        for(unsigned int i=0; i<len; i++){
            temp[i]=array[i];
        }
        delete [] array;
        array=temp;
    }
}
};

ここでは、メモリ関連のコードのみを掲載しました。

指定した行で Valgrind がメモリ リークを報告している理由がわかりません。古い配列の内容を拡大された配列にコピーした後、2行後に古い配列を削除します。

また、デストラクタで delete[] 関数のコメントを外すと、例外が発生 double free or corruptionし、Valgrind が無効な削除 (再削除を意味する) を報告するので、完全に当惑します。何か案は?

編集: 早い返信ありがとうございます! コメントを読んだ後、問題はクラスにあるのではなく、Array クラスを引数として呼び出していた別の関数にあることがわかりました。この関数の呼び出しを削除し、クラスに削除呼び出しを追加すると、メモリ リークは発生しません。これが私の機能です:

template <typename T>
void printContents(Array<T> ar){
for(unsigned int i=0; i<ar.size(); i++){
    cout<<"Content at i in array = " << ar.at(i) << endl;
}
}

Rule of Three (chris に感謝) と Grizzly が投稿した回答を読んだ後、delete[] が無効である理由がわかりました。コピー コンストラクターをオーバーロードしていないため、浅いコピーが発生したため、配列ポインターがar のポインターに割り当てられ、ar がスコープ外のときに delete[] が呼び出され、メインで削除が行われました。機能無効。したがって、私は例外を受けていました。削除を削除すると、配列は明らかに割り当てられたままになり、メモリ リークが発生します。

助けてくれてありがとう、グリズリーの答えを正しいと投票しました。

4

1 に答える 1

2

delete[]デストラクタを呼び出さないと、メモリ リークが発生します。つまりcheckMax、オブジェクトで最後に呼び出したときに割り当てられた配列 (オブジェクトの「最終的な」配列) は呼び出されません。したがってdelete[]、デストラクタでコメントを解除する必要があることを解決するには

あなたが言ったように、これはあなたにダブルフリーの問題を与えるでしょう. これは、3 のルールの違反に基づいています (C++03 では 3 のルールであり、C++11 では状況はそれほど明確ではありませんが、このシナリオでは 3 のルールで十分です)。あなたの問題を解決します)。基本的に 3 つのルールでは、カスタム デストラクタ、コピー コンストラクタ、または代入演算子を定義するときは、それらすべてを定義する必要があります。この場合、Arrayどこかのコピーを行っている可能性があります。つまり、両方のインスタンスに同じポインターが含まれており、デストラクタでそれを削除しようとします。同じポインターで delete を 2 回呼び出すと、エラーになります。この問題を解決するには、配列のディープ コピーを行う (新しいメモリを割り当てて内容をコピーする) カスタム コピー コンストラクターと代入 op を定義する必要があります。以上)。

すべてはさておき、個人的には、スマートポインターから始めて、後でC++をよりよく理解してから、手動のメモリ管理を試してみることをお勧めします。

于 2013-05-25T13:55:37.893 に答える