2011-07-08 6 views
2

私のC++アプリケーションで、デバッグに問題があるとのエラーが発生しています。私はオンラインで見ましたが、私は割り当て/割り当て解除のすべてを正しい方法でやっているようです。ここに私のコードです:テンプレートを使用したダイナミック2D配列の割り当て解除

未処理の例外:とすぐに、変数「myMatrix」として

template <typename T> 
class Matrix 
{ 
private: 
    int _rows; 
    int _cols; 
    T** _matrix; 
public: 
    Matrix(int r, int c); 
    ~Matrix(); 
    T GetValue(int r, int c); 
}; 

template <typename T> 
Matrix<T>::Matrix(int r, int c) 
{ 
    _rows = r; 
    _cols = c; 

    _matrix = new T*[_rows]; 
    for(int i = 0; i < _rows; i++) 
     _matrix[i] = new T[_cols]; 

    for(int i = 0; i < _rows; i++) 
     for(int j = 0; j < _cols; j++) 
     _matrix[i][j] = NULL; 
} 

template <typename T> 
Matrix<T>::~Matrix() 
{ 
    for(int i = 0; i < _rows; i++) 
     delete [] _matrix[i]; 
    delete [] _matrix; 
} 

template <typename T> 
T Matrix<T>::GetValue(int r, int c) 
{ 
    if(r < 0 || r >= _rows || c < 0 || c > _cols) 
    { 
     throw -1; 
     return NULL; 
    } 

    return _matrix[r][c]; 
} 

そして、私のクライアントコード...

int main() 
{ 
    Matrix<int> myMatrix(3, 3); 
    myMatrix.GetValue(1, 1); 
    // myMatrix.~Matrix(); // Don't do this anymore 
} 

スコープの外に出る、私はこのエラーを取得します0x103159da(msvcr1000d.dll)...アクセス違反は、場所0xfeeefee2を読み取っています。
そして、 "dbgdel.cpp"ファイルに持ち込まれました。 _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead-> nBlockUse));

助けてください!


EDIT:

さて、私はいくつかの情報を提供することを怠っ。以下を参照してください:

私は「Tドット(マトリックス)」と呼ばれる追加のメソッドを持っています。また、_colsと_rowsのgetterである2つのメソッド「Columns()」と「Rows()」があります。また、 "SetValue(int r、int c、T value)"というメソッドは_matrix[r][c] = valueと設定します。私はこれらのために実装が必要であるとは思わない。

template <typename T> 
T Matrix<T>::Dot(Matrix<T> m) 
{ 
    if(_cols > 1 || m.Columns() > 1 || _rows != m.Rows()) 
    { 
     throw -1; 
     return NULL; 
    } 

    T value = 0; 
    for(int i = 0; i < _rows; i++) 
    { 
     value += _matrix[i][0] * m.GetValue(i, 0); 
    } 
    return value; // Whoops, this was here, just forgot to type it 
} 

とクライアント...

int main() 
{ 
    Matrix<int> intM1(3, 1); 
    Matrix<int> intM2(3, 1); 

    intM1.SetValue(0, 0, 1); 
    intM1.SetValue(1, 0, 1); 
    intM1.SetValue(2, 0, 1); 
    intM2.SetValue(0, 0, 1); 
    intM2.SetValue(1, 0, 1); 
    intM2.SetValue(2, 0, 1); 

    std::cout << intM1.Dot(intM2) << endl; 
} 

これは上記と同じエラーが発生しますが、 "ドット()" 関数が呼び出されたときにのみ。

+1

あなたのメイン関数からmyMatrix。〜Matrix()を削除しようとしましたか?デストラクターは、オブジェクトがスコープから外れると自動的に呼び出されます。オブジェクトを明示的に呼び出すべきではありません。 – Connman

+0

@コーンマン。ありがとう、私はデストラクタが自動的に呼び出されたことを知っていたが、私はそこにテストとして入れた。私は、私がそこにそれを持っていなくてもエラーを受けていたと誓っていたかもしれませんが、もちろん私はこの質問をしたので、彼らは姿を消しました。私は数時間前のことを再現しようとしています。 – Eric

+0

@エリックあなたがそれを使用していない場合は、そのような誤解を招くようなコードをあなたの質問に入れないでください。編集された答えを参照してください。 – iammilind

答えて

2

をあなたの編集では、ここでの問題は、(あなたの最後の質問に私の答えを参照してくださいまだコピーコンストラクタと代入演算子の欠如であります)。問題は、Matrixを関数に渡すと、コピーコンストラクタが呼び出されてコピーが作成されますが、定義していないので、C++はデフォルトのコピーコンストラクタを使用します。その結果、古いMatrixと同じ要素へのポインタを共有する新しいMatrixが得られます。この新しいMatrixが有効範囲外になると、デストラクタが起動し、もう一方のMatrixで使用されている配列がクリーンアップされます。元のMatrixが範囲外になり、クリーンアップされると、既に削除された配列を削除しようとし、クラッシュを引き起こします。

これを修正するには、リソースを正しく複製するコピーコンストラクタと代入演算子を実装する必要があります。あなたがデストラクタを持っているならば、この種のバグを防ぐためにコピーコンストラクタと代入演算子も必要であるというルールの3つのルールがあります。これらの不足している機能を実装して、問題が解消するかどうか確認してください。

+0

この問題を解決するための優れた説明と方向性に感謝します。以前混乱して申し訳ありません。 – Eric

+1

これは間違いありませんが、実際に行列のコピーを 'Dot'の引数として渡したいのかどうかを考えてみてください。私はこれが 'const'リファレンスであると期待しています。' T Matrix :: Dot(Matrix const&m)// etc'です。この方法で 'Dot'を呼び出すたびに行列全体をコピーすることはありません。 –

+1

@Darren Engwirda-絶対に。それでも、不足しているコピー機能は、このようなバグが一見有効なコードで表示されるのを防ぐため、できるだけ早く処理しなければなりません。 – templatetypedef

3

は、あなたがスタック上にmyMatrixを割り当てられましたが、明示的にデストラクタを呼び出してはいけないので、変数がスコープの外に出るときdtorは自動的に、すなわちmain()リターンを呼び出されます。

+1

@Templatetypedef:ええと、 'dtor'を明示的に呼び出す場所は、' new'というプレースメントを使って作成したオブジェクトをクリーンアップすることだけです。 –

+0

皆さん、ありがとうございました。可能であれば、私の編集を見て、追加のコメントを提供してください。 – Eric

1

編集

ここでエラーです:

T Matrix<T>::Dot(Matrix<T> m); 

この関数はTを返す必要があり、それが最終的に戻っていません! Put、

return value; 

解決する必要があります。また、いくつかの提案があります:エラーが発生しやすい値でMatrix<T> m;を渡しています。 mと元のintM2の両方が同じ_matrixを指しているためです。したがって、mが範囲外になると、それはすべてdelete[]になります。 intM2が有効範囲外になると、同じメモリを再度削除するとになります。再びクラッシュする。

コピーコンストラクタ(常にprivateまたは適切なコピーコード)を指定する必要があります。現在のところ、定義を次のように変更します。

T Matrix<T>::Dot(Matrix<T> &m); // pass `m` by reference 

これですべてのエラーが解決されます。 (あなたはそれのためにあなたがGetValue() constを変更する必要があり、またconst Matrix<T> &mを通過するように選択することができます。)

+0

ありがとうございます。私は間違った質問を間違って尋ねたので気分が悪いです。私の編集内容を読んで、あなたの専門知識を提供してください。 – Eric

関連する問題