2011-07-08 42 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