web-dev-qa-db-ja.com

C ++演算子+および演算子+ =オーバーロード

言語の理解を深めるために、c ++で独自のマトリックスクラスを実装しています。 + =演算子が機能している場合は、+演算子で使用することをどこかで読みました。だからそれは私が持っているものです:

template <class T>
const Matrix<T>& Matrix<T>::operator+(const Matrix<T> &R){

    Matrix<T> copy(*this);
    return copy += R;
}

そして、これが+ =演算子のオーバーロードです。

template <class T>
const Matrix<T>& Matrix<T>::operator+=(const Matrix<T> & second_matrix){
    //Learn how to throw errors....
    if (rows != second_matrix.getNumRows() || cols != second_matrix.getNumCols()){throw "Dimension mismatch.";}
    int i,j;
    for (i = 0; i < rows; i++){
        for (j = 0; j < cols; j++){
            data[i][j] += second_matrix.get(i,j);
        }
    }
    return *this;
}

+ =は問題なく使用できます(たとえば、a + = b;エラーは返されません)。ただし、+演算子(たとえば、a = b + c;)を呼び出すと、次のようになります。

test.cpp.out(77055) malloc: *** error for object 0x300000004: pointer being freed was not allocated

完全を期すために、これが私のデストラクタです。

template <class T>
Matrix<T>::~Matrix(){
    for (int i = 1; i < rows; i++){
        delete[] data[i]; }
    delete[] data;
}

私はC++を数年間オンとオフで使用していますが、それでもポインタを追跡するのに問題が発生することがあります。私はそれが正常であることを願っています...どんな助けも素晴らしいでしょう。ありがとう!

編集:これが私のコピーコンストラクタです。データ配列を解放するように設定されていましたが、削除しました。今、私はセグメンテーション違反を取得します。

template <class T>
Matrix<T>::Matrix(const Matrix<T>& second_matrix){

    rows = second_matrix.getNumRows();
    cols = second_matrix.getNumCols();
    data = new T*[rows];

    int i,j;
    for (i = 0; i < rows; i++){
        data[i] = new T[cols];
    }
    for (i = 0; i < rows; i++){
        for (j = 0; j < cols; j++){
            data[i][j] = second_matrix.get(i,j);
        }
    }

}
9
jakev

operator+()は、操作の結果を保持する新しい(ローカルで宣言された)インスタンスであるため、参照型を返さないでください。

22

これが3Dレンダリング/シミュレーションのマトリックスである場合、そのようなメモリを動的に割り当てないことをお勧めします。最終的にメモリがいたるところに分散し、キャッシュの問題が発生する可能性があります。また、潜在的なメモリバグにつながります。

template <typename T>
class Matrix
{
   public:
      T   m_Data[4][4];
};

または4x4以外のものが必要な場合

template <typename T, unsigned int rows, unsigned int columns>
class Matrix
{
   public:
      T   m_Data[rows][columns];
};

次に、Matrixオブジェクトを動的に割り当てます。

2
AlexF

これは私がそのような演算子を行列クラスに実装した方法です。これはベクトルクラスに基づいています。いくつかの演算子を定義したら、他のすべての演算子を最も単純な演算子で定義する必要があります。

Matrix::Matrix(const Matrix& rMatrix) :
    _iRows(rMatrix._iRows), _iColumns(rMatrix._iColumns), _pVector(0)
{
    _pVector = new Vector[_iRows];
    for (int i = 0; i < _iRows; i++) { _pVector[i] = rMatrix._pVector[i]; }
}

Matrix& Matrix::operator=(const Matrix& rMatrix)
{
    if (this != &rMatrix)
    {
        if (0 != _pVector) { delete[] _pVector; pVector = 0; }
        _iRows = rMatrix._iRows;
        _iColumns = rMatrix._iColumns;
        _pVector = new Vector[_iRows];
        for (int i = 0; i < _iRows; i++) { _pVector[i] = rMatrix._pVector[i]; }
    }
    return *this;
}
Matrix& Matrix::operator+=(const Matrix& rMatrix)
{
    *this = *this + rMatrix;
    return *this;
}

Matrix Matrix::operator+(const Matrix& rMatrix) const
{
    Matrix matrix(_iRows, _iColumns);
    ValidateSizes(rMatrix);
    for (int i = 0; i < _iRows; i++) { matrix._pVector[i] = _pVector[i] + rMatrix._pVector[i]; }
    return matrix;
}

Matrix operator+(const Matrix& rMatrix, double dNum)
{
    Matrix matrix(rMatrix._iRows, rMatrix._iColumns);
    matrix.ValidateSizes(rMatrix);
    for (int i = 0; i < matrix._iRows; i++) { matrix._pVector[i] = dNum + rMatrix._pVector[i]; }
    return matrix;
}

Matrix operator+(double dNum, const Matrix& rMatrix)
{
    return operator+(rMatrix, dNum);
}

bool Matrix::ValidateSizes(const Matrix& rMatrix) const
{
    if (_iRows != rMatrix._iRows) { /* THROW EXCEPTION */ }
    if (_iColumns != rMatrix._iColumns) { /* THROW EXCEPTION */ }
    return true;
}
2
ArBR