2011-07-08 41 views
2

我在我的C++應用程序中遇到了一個錯誤,我在調試時遇到了麻煩。我在網上看過,而且我似乎是以正確的方式完成我的所有分配/釋放。這裏是我的代碼:用模板取消分配動態二維數組

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 
} 

只要變量「myMatrix的」超出範圍,我得到這個錯誤:

未處理的異常在0x103159da(msvcr1000d.dll)...訪問衝突讀取位置0xfeeefee2。
而我被帶到文件「dbgdel.cpp」 _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead-> nBlockUse));

請幫忙!


編輯:

好了,我忘了給一些信息。請看下面:

我有一個叫做「T Dot(矩陣)」的附加方法我也有兩個叫做「Columns()」和「Rows()」的方法,它們只是_cols和_rows的getters。還有一個名爲「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

@Connman。謝謝,我知道析構函數被自動調用,但我把它作爲一個測試。我可以發誓,即使我沒有在那裏發現錯誤,但當然,現在他們已經消失了,我已經問過這個問題。我將嘗試重現我幾小時前的事情。 – Eric

+0

@Eric,如果您不使用它,請不要在您的問題中輸入這樣的誤導性代碼。見編輯的答案。 – iammilind

回答

2

隨着您的編輯,這裏的問題仍然是缺乏一個拷貝構造函數和賦值操作符(見我的回答你最後一個問題)。問題是,當你通過值傳入Matrix到一個函數中時,複製構造函數被調用來創建副本,但由於你沒有定義一個C++將使用默認的複製構造函數,它只是一個淺拷貝。因此,你最終會得到一個新的Matrix,它與舊的Matrix共享一個指向相同元素的指針。當這個新的Matrix超出範圍時,其析構函數將會觸發,清理其他Matrix使用的數組。當原始Matrix然後超出範圍並被清理後,它將嘗試刪除已刪除的陣列,導致崩潰。

要解決此問題,您需要實現正確複製資源的複製構造函數和賦值運算符。有一個經驗法則叫三規則,它說如果你有一個析構函數,你還需要一個拷貝構造函數和賦值操作符來防止這些類型的錯誤。嘗試實施這些缺失的功能,並查看問題是否清除。

+0

謝謝你解決這個問題的出色解釋和方向。對不起,以前的混亂。 – Eric

+1

雖然這是完全正確的,但您可能需要考慮是否真的想將矩陣的副本作爲參數傳遞給「Dot」。我希望這是一個'const'參考:'T Matrix :: Dot(Matrix const&m)// etc'。這樣你每次調用'Dot'時都不會複製整個矩陣。 –

+1

@Darren Engwirda-絕對。儘管如此,還是應該儘快處理缺失的拷貝功能,以防止這樣的錯誤出現在看似有效的代碼中。 – templatetypedef

3

不要明確調用析構函數,因爲您已經在堆棧中分配了myMatrix,所以當變量超出範圍時,即main()返回時,將自動調用dtor

+1

@Templatetypedef:是的,只有*我可以想到的地方,你可以明確地稱之爲'dtor',是清理使用放置'new'創建的對象... –

+0

謝謝大家的好評。請參閱我的編輯並儘可能提供其他意見。 – Eric

1

編輯

以下是錯誤:

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

該函數返回T,它不是在最後回國!放,

return value; 

它應該被解決。還有一些建議:您正在通過值爲錯誤的值Matrix<T> m;。因爲複製的m和原始intM2將指向相同的_matrix。所以當m超出範圍,它會delete[]的一切。當intM2超出範圍時,將再次刪除相同的內存。這又一次崩潰。

因此,您應該始終指定複製構造函數(或者作爲private或使用正確的複製代碼)。截至目前改變的定義爲,

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

這將解決您的所有錯誤。 (您可以選擇通過const Matrix<T> &m通也,爲您可能需要更改GetValue() const

+0

謝謝。我不好意思,因爲我不小心問錯了問題。您能否閱讀我的編輯並提供您的專業知識? – Eric