使用模板释放动态2D数组

时间:2011-07-08 02:27:08

标签: c++ arrays memory-management dynamic

我在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-&GT; nBlockUse));

请帮忙!


编辑:

好的,我忽略了提供一些信息。请参阅以下内容:

我有一个名为“T Dot(Matrix)”的附加方法我还有两个名为“Columns()”和“Rows()”的方法,它们只是_cols和_rows的getter。还有一个名为“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;
}

这会产生与上面相同的错误,但仅在调用“Dot()”函数时才会生成。

3 个答案:

答案 0 :(得分:3)

不要显式调用析构函数,你已经在堆栈上分配了myMatrix,因此当变量超出范围时,dtor将被自动调用,即main()回报。

答案 1 :(得分:2)

通过编辑,这里的问题仍然是缺少复制构造函数和赋值运算符(请参阅我对上一个问题的回答)。问题是当你将Matrix by值传递给一个函数时,调用复制构造函数来制作副本,但是由于你没有定义一个C ++将使用默认的复制构造函数,它只是浅复制。因此,您最终会得到一个新的Matrix,它共享指向与旧Matrix相同元素的指针。当这个新的Matrix超出范围时,它的析构函数将触发,清理另一个Matrix使用的数组。当原始Matrix超出范围并被清理时,它将尝试删除已删除的数组,从而导致崩溃。

要解决此问题,您需要实现正确复制资源的复制构造函数和赋值运算符。有一个名为Rule of Three的经验法则,如果你有一个析构函数,你还需要一个复制构造函数和赋值运算符来防止这些类型的错误。尝试实现这些缺失的功能,看看问题是否清除。

答案 2 :(得分: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。)