1

次元を 2 次元配列で渡すという C++ の要件に対する煩わしさから、テンプレート化された Matrix クラスに取り組むことになりました。私は C# で少しコーディングしているので、ここでは少しさびていると思います。

問題は、2 次元配列を削除しようとしているデストラクタに到達するとすぐにヒープ例外が発生することです。

どんな助けもありがたく受け入れました!

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

2 に答える 2

3

これはバグです:

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

ループはnRowsではなくまでにする必要がありnColsます。

それ以外に、2 次元配列の割り当てに飽きたときに私がしたことについてお話ししましょう。私は3次元配列をしなければなりませんでした。私mapは座標からマッピングされた を使用しました - x、y、z を必要な型に保持する構造体。

すばやく作業でき、割り当てや割り当て解除の必要がありませんでした。座標への割り当ては、次のように単純に行われました

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

もちろん、Coord構造体を定義して をオーバーロードする必要が< operatorありましたが、3 次元配列の割り当てと割り当て解除を試みるよりも、その方が便利であることがわかりました。

もちろん、このスキームが十分に高速かどうかを確認する必要があります。OpenGL を使用して大きな立方体内にセルを描画するために使用しましたが、まったく不満はありませんでした。

于 2012-12-02T08:01:55.180 に答える
1

バグに関しては、@CodeChords_man が正しく説明してくれました。実施にあたっての注意事項があります。この素晴らしい FAQ の投稿に目を通すことをお勧めします。

100% 確実でない限り、動的メモリ割り当てを使用しないでください。

  1. あなたは本当にそれが必要です
  2. あなたはそれを実装する方法を知っています

私は最初のことを知りません、そしてパフォーマンスがあなたにとってどのように重要であるか. しかし、2 番目については、少なくとも3 つのルールに違反しています。あなたのクラスは使用するのが非常に安全ではありません。コピーすると、メモリ バッファが二重に削除されます。

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

このクラスは動的メモリ割り当てを使用していないため、安全にコピーして割り当てることができます。この場合、nRowsandを明示的に保存する必要もありません。代わりにandnColsを使用できます。_body.size()_body[0].size()

ベクトルの基になるベクトルに関しては、同じ[i][j]構造を使用して逆参照されます。と で簡単に反復できbegin()ますend()。また、何らかのルーチンで絶対に生ポインタを使用する必要がある場合は、いつでも でアクセスできます&row[0]

唯一の困難は、簡単に に変換できないことMatrixBodyですT**。しかし、よく考えてみてください。実際にはまったく使用する必要がないかもしれませんT**

于 2012-12-02T10:11:08.427 に答える