2012-03-26 4 views
0

私はMatrixMxNというクラスを持っています。コンストラクタには、パラメータの行、列があります。私はこれを行うと、問題を取得していたが、私は、寸法の行、列を有する2次元アレイのメモリを割り当てようとしてい.. メモリ(実行時)を正しく管理する方法C++

{ 
    MatrixMxN coord(4, 1); 
    coord(0, 0) = 1.0; 
    coord(0, 1) = 1.0; 
    coord(0, 2) = 1.0; 
    coord(0, 3) = 1.0; 
} 

ザ(Iは各エントリに値を割り当てる括弧演算子をオーバーライドしています)私が直面している問題は、デコンストラクタが呼び出されたときにエラーが発生したようです。 -

WindowsがMatrixTest.exeでブレークポイントをトリガしました。 これは、ヒープが破損している可能性があります。これは、MatrixTest.exeまたはロードしたDLLのバグを示します。

私の行列クラスのスニペットは次のとおりです。

typedef float* floatPtr; 
class MatrixMxN { 
private: 
    float** entry; 
    int rows; 
    int cols; 

public: 
    MatrixMxN(int r, int c) { 
     rows = r; 
     cols = c; 

     //Create a matrix 
     if(rows > 0 && cols > 0) { 
      //Declare an array of pointers 
      entry = new floatPtr[rows]; 

      //Declare each array 
      for(int i=0; i<rows; i++) { 
       entry[i] = new float[cols]; 
      } 

      this->empty(); 
     } 
    } 
    ~MatrixMxN() { 
     //Free memory 
     for(int i=0; i<rows; i++) { 
      delete[] entry[i]; 
     } 

     //Free pointers array 
     delete[] entry; 
    } 

    void empty() { 
     for(int i=0; i<rows; i++) { 
      for(int j=0; j<cols; j++) { 
       entry[i][j] = 0; 
      } 
     } 
    } 

    // Assignment operator 
    void operator=(MatrixMxN& other) { 
     //Check they are the same size 
     assert(rows == other.rows && cols == other.cols); 

     //Copy 
     for(int i=0; i<rows; i++) { 
      for(int j=0; j<cols; j++) { 
       entry[i][j] = other(i, j); 
      } 
     } 
    } 
    float& operator()(const int irow, const int icol) { 
     //Check they are not out of bounds 
     assert ((irow >= 0 && irow < rows) || (icol >= 0 && icol < cols)); 

     return entry[irow][icol]; 
    } 
... 

エラーをトリッピングする部分は、ループ内のデコンストラクタにあります。

//Free memory 
    for(int i=0; i<rows; i++) { 
     delete[] entry[i]; 
    } 

dbgheap.cファイルは、I = 0 [i]は[]エントリを削除する最初の試みにエラーをスロー。行列を印刷するときは意図したとおりにうまく動作しますが、ここではエラーが発生しているようです。うまくいけば、私は十分な情報をここに提供してくれた、ありがとう。

EDIT1:含ま代入演算子のオーバーロード EDIT2:付属()過負荷

回答: 問題は、私は、私はそれを持っていたかではなく、転置的に値を入力しました。メモリはここで壊れていた、すべての助けに感謝します。

+0

さて、コンストラクタに 'else entry = NULL'がありませんが、それ以外は'() 'がオーバーロードされていますか?そうでない場合、 'coord(0、0)= 1.0;は何ですか? –

+0

はい()をオーバーロードしました。上記の編集を含めました^ –

答えて

2

この月原因ではありませんが、クラスMatrixMxNに定義されたコピーコンストラクタまたは代入演算子がありません。それらを定義するか、またはprivateと宣言してオブジェクトをコピーできないようにします。

rows > 0しかしcols <= 0の場合、この例では問題ではありませんが、デストラクタの初期化されていないポインタでdelete[]が呼び出されます。コンストラクタでentryは、rows > 0 && cols > 0の場合にのみ初期化されます。rows > 0しかしcols <= 0場合はデストラクタで次forループはまだdelete[] entry[i];呼び出し:

for(int i=0; i<rows; i++) { 
    delete[] entry[i]; // entry unitialized 
} 

続い:

EDIT
delete[] entry; // entry unitialized 

operator()このassertが間違っている

assert ((irow >= 0 && irow < rows) || (icol >= 0 && icol < cols)); 
それは &&を使用する必要があります

assert ((irow >= 0 && irow < rows) && (icol >= 0 && icol < cols)); 
+0

さて、代入演算子関数も含めました。 assertは上の例でエラーをスローしません^しかし –

+0

コピーコンストラクタが定義されていますか? – hmjd

+0

私はそれを定義していませんか?これはMatrixMxN(MatrixMxN&copy){...などです。 –

2

あなたのempty()メソッドは、行と列の代わりに行と行を処理しています。これはメモリを破壊しています。これはエントリを削除すると捕捉されます。

あなたが要素を割り当てているとき、それはあなたのインデックスはあなたの例では転置されて表示されますので、あなたはまた、メモリを破損することができる

coord(0, 0) = 1.0; 
coord(0, 1) = 1.0; 
coord(0, 2) = 1.0; 
coord(0, 3) = 1.0; 

をあなたは意味しない:

coord(0, 0) = 1.0; 
coord(1, 0) = 1.0; 
coord(2, 0) = 1.0; 
coord(3, 0) = 1.0; 
+0

要素を割り当てるときに、行と列が転置されているように見えます。 –

+0

:$はい、問題は私が要素を転置したことです。ありがとう!病気をもう一度チェックしてください。 –

3

あなたはワンステップでメモリを割り当てる必要があります:すべてのアクセスでアクセス位置を計算し、その後、M * N個のfloatの配列を割り当てます。 割り当て解除も同様に簡単です:delete [] matrix;あなたは適切なコピーコンストラクタを欠場:

+2

これは、行列のすべてのメモリを連続領域としてアクセスできるというメリットがあるため、メモリの断片化の場合にパフォーマンスが向上する可能性があります。 – SirDarius

+1

これは実際には行列の使い方によってはもっと良いかもしれませんが、このようにして、エントリを格納するために 'std :: vector'を使うべきです。 – leftaroundabout

3

あなたのクラスは、潜在的にあなたがそこに大きな悪と過ちを持つメモリをリークし、行動

を未定義ました。コンパイラは、正しいのものを生成します:あなたのポインタをコピーします。しかし、それはあなたが望むものではありません。代わりに、コピーコンストラクタは新しいメモリを割り当て、配列の内容をコピーする必要があります。

つまり、現在の実装では、メモリが簡単にリークされ、二重削除が実行されます。

選択肢:

  • 読むだけでなくコピーのセマンティクスを定義し、自らそのメモリを管理しているThe Rule of Three
  • 使用標準コンテナ(std::vector)、上。あなたが持っているのは標準コンテナであれば、デストラクタやコピーコンストラクタやコピーの代入は一切必要ありません(行列クラスを多相的に削除しない場合)。

また、スタイルのアドバイスこのようにemptyを使用してください。すべての標準コンテナには、あなたとはまったく異なる何かを行うempty()メソッドがあります。

+0

しかしそれは誤りではありませんでした。実際にコピーを作成し、そのクラスを関数の引数として使用し、std :: vectorsなどに格納するだけで、コピーコンストラクタが必要です。この例ではエラーはありませんでしたそこ。 –

+0

ありがとう、3つのルールを読んでいない。 –

+0

@DannyBirch:デフォルトでは、標準のコンテナを使用します。家の中の例外では、3つのルールに正しく従うことは非常に重要ではありません。また、 "RAII"(Resource Acquisition Is Initialization)も読んでいます。これは、多くのpplがC++の第1の理由です。 –

関連する問題