2012-12-02 20 views
1

对C++要求在二维数组中传递维度的烦恼让我开始了一个模板化的Matrix类。我一直在用C#编写代码,所以我确信我在这里有点生疏。删除模板化的C++二维数组

问题是,只要我点击析构函数,试图删除二维数组,就会得到一个堆异常。

任何帮助感激地接受!

template <typename T> 
class Matrix { 
public: 
    Matrix(int m, int n) : nRows(m), nCols(n) { 
     pMatrix = new T * [nRows]; 
     for (int i = 0; i < nCols; i++) { 
      pMatrix[i] = new T[nCols]; 
     } 
    } 
    ~Matrix() { 
     if (pMatrix != NULL) { 
      for (int i = 0; i < nRows; i++) { delete[] pMatrix[i]; } 
      delete[] pMatrix; 
     } 
    } 
    T ** GetMatrix() const { return pMatrix; } 
    T * Row(int i) const { return pMatrix[i]; } 
    inline T Cell(int row, int col) const { return pMatrix[row][col]; } 
    inline int GetNRows() const { return nRows; } 
    inline int GetNCols() const { return nCols; } 
private: 
    int nRows, nCols; 
    T ** pMatrix; 
}; 
+0

代码似乎不错。 – Healer

+1

为什么你需要返回'T **'和'T *'?对我来说,这似乎暴露了内部实现细节。你可以通过使用一个'std :: vector'并使用索引来访问来简化代码。 – juanchopanza

+0

完全同意胡安。通过使用'std :: vector <>'和一个简单的'i * cols + j'来获取'[i] [j]'元素,可以使*显着更简单。您唯一会遗漏的是能够执行双括号解引用,甚至可以用返回行迭代器的创意子类来征服。 – WhozCraig

回答

1

关于该错误,@CodeChords_man解释它是正确的。我有关于实施的说明。我建议通过this wonderful FAQ post

你不应该使用动态内存分配,除非你是100%肯定

  1. 真的需要
  2. 你知道如何实现它

我不知道第一,以及表现如何对你至关重要。但至于第二,你至少违反了rule of three。你的课是非常不安全的。如果复制它,内存缓冲区将被双重删除。

你不应该害怕使用STL容器,它们是快速和优化的。至少std::vector,它在许多情况下与原始指针一样快。您可以使用std::vector如下重写你的类:

template <typename T> 
class Matrix { 
public: 
    typedef std::vector<T> MatrixRow; 
    typedef std::vector<MatrixRow> MatrixBody; 

    Matrix(int m, int n) : nRows(m), nCols(n), _body(m, MatrixRow(n)) {} 

    const MatrixBody& GetMatrix() const { return _body; } 
    const MatrixRow& GetRow(int i) const { return _body[i]; } 

    inline T Cell(int row, int col) const { return _body[row][col]; } 
    inline int GetNRows() const { return nRows; } 
    inline int GetNCols() const { return nCols; } 
private: 
    int nRows, nCols; 
    MatrixBody _body; 
}; 

因为此类不使用动态内存分配,它是安全的复制和分配。在这种情况下,您也不需要明确存储nRowsnCols;您可以改用_body.size()_body[0].size()

关于载体的基础载体,它使用相同的[i][j]结构解除引用。它很容易与begin()end()迭代。如果您绝对需要在某些例程中使用原始指针,则可以始终使用&row[0]访问它。

唯一可能的困难是,你不能很容易地转换到MatrixBodyT**。但想两次,也许你根本不需要使用T**

+0

在所有的方面都不能同意你的观点!我修复了这个错误;我现在要使用STL之后去。我最初来自STL无法使用(大小)的深度嵌入式环境。这是一个很好的提示,我会尝试一下,让你知道它是如何工作的。 – Dana

+0

很高兴为您服务!考虑upvoting甚至接受我的回答呢:) – Mikhail

+0

我现在越来越贪婪 - 我要去弄清楚如何重载[]里,所以我没有用笨拙“GetMatrix”语法:) – Dana

3

这是错误:

for (int i = 0; i < nCols; i++) { 
     pMatrix[i] = new T[nCols]; 
} 

循环应该到nRows,不nCols

除此之外,让我告诉你一些当我厌倦分配二维数组时所做的一些事情。我不得不做一个三维阵列。我使用了一个map,它是从一个坐标映射而来的 - 一个把x,y,z保存为我想要的类型的结构。

我工作的很快,不需要分配或解除分配。分配给一个坐标被简单地完成由

mymap[Coord(x, y, z)] = whatever... 

当然我需要定义Coord struct和重载< operator,但是我发现这样不是试图分配和释放3-d阵列更comvenient。

当然你需要检查这个方案对你来说是否足够快。我用它使用OpenGL在一个大立方体内绘制细胞,并且根本没有任何抱怨。

+0

你是对的 - 那是我的错误! – Dana