简体   繁体   English

删除模板化的C ++二维数组

[英]Deleting templated C++ 2-dimensional array

Annoyance over C++'s requirement to pass a dimension in a 2-d array got me working on a templated Matrix class. 对C ++在二维数组中传递维度的要求的烦恼使我开始研究一个模板化的Matrix类。 I've been coding in C# for a bit, so I'm sure I'm a little rusty here. 我已经在C#编写了一段时间,所以我确定我在这里有点生疏。

Issue is, I get a heap exception as soon as I hit the destructor, which is trying to delete the 2-d array. 问题是,我一打到析构函数就得到一个堆异常,它试图删除二维数组。

Any help gratefully accepted! 感谢任何帮助!

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;
};

This is the bug: 这是错误:

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

The loop should be until nRows , not nCols . 循环应该是nRows ,而不是nCols

Other than that, let me tell you about something I did when I got tired of allocating 2-d arrays. 除此之外,让我告诉你我厌倦了分配二维阵列时所做的事情。 I had to do a 3-d array. 我不得不做一个三维阵列。 I used a map , that mapped from a coordinate - a struct holding x, y, z to the type I wanted. 我使用了一个从坐标映射的map - 一个包含x,y,z的结构到我想要的类型。

I worked fast, and no need to allocate or deallocate. 我工作得很快,不需要分配或解除分配。 Assigning to a coordinate was simply done by 分配到坐标只是通过

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

Of course I needed to define the Coord struct and overload the < operator , but I found that way more comvenient than trying to allocate and deallocate a 3-d array. 当然我需要定义Coord结构并重载< operator ,但我发现这比尝试分配和释放3-d数组更方便。

Of course you will need to check if this scheme is fast enough for you. 当然,您需要检查此方案是否足够快。 I used it to draw cells within a big cube using OpenGL and had no complaints at all. 我用它来使用OpenGL在一个大的立方体内绘制单元格,并且完全没有任何抱怨。

Concerning the bug, @CodeChords_man explained it right. 关于这个bug,@ CodeChords_man解释得对。 I have notes on implementation. 我有关于实施的说明。 I recommend to look through this wonderful FAQ post . 我建议您浏览这篇精彩的常见问题解答帖子

You should not use dynamic memory allocation unless you are 100% sure that 除非您100%确定,否则不应使用动态内存分配

  1. You really need it 真的需要它
  2. You know how to implement it 你知道如何实现它

I don't know of the first, and how the performance is crucial for you. 我不知道第一个,以及性能如何对您至关重要。 But as for the second, you at least violated the rule of three . 但至于第二个,你至少违反了三个规则 You class is very unsafe to use. 你上课是非常不安全的。 If you copy it, the memory buffer will then be double-deleted. 如果复制它,则会双重删除内存缓冲区。

You should not afraid to used STL containers, they are fast and optimized. 您不应该害怕使用STL容器,它们快速且优化。 At least the std::vector , it is as fast as the raw pointer in many scenarios. 至少std::vector ,它在许多情况下和原始指针一样快。 You can rewrite you class using std::vector as follows: 您可以使用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;
};

Since this class is not using dynamic memory allocation, it is safe to copy and assign. 由于此类未使用动态内存分配,因此可以安全地进行复制和分配。 You also don't need to explicitly store nRows and nCols in this case; 在这种情况下,您也不需要显式存储nRowsnCols ; you can use _body.size() and _body[0].size() instead. 你可以使用_body.size()_body[0].size()代替。

Concerning underlying vector of vectors, it is dereferenced using the same [i][j] construction. 关于向量的基础向量,使用相同的[i][j]构造对其进行解引用。 It is easily iterated with begin() and end() . 它很容易用begin()end()迭代。 And if you absolutely need to use the raw pointer in some routine, you can always access it with &row[0] . 如果您绝对需要在某个例程中使用原始指针,则始终可以使用&row[0]访问它。

The only possible difficulty is that you cannot easily convert MatrixBody to T** . 唯一可能的困难是你不能轻易地将MatrixBody转换为T** But think it twice, maybe you don't really need to use T** at all. 但想想它两次,也许你根本不需要使用T**

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM