実行中のテストのために行列 (およびベクトル) 計算を行い、C++ をさらに学習するためのクラスを作成しています。クラスは次のようになります。
class utlMatrix
{
private:
int num_rows;
int num_cols; // number of columns
double **data; // array of pointers to the data
public:
// default constructor, with initialization
utlMatrix() : num_rows(0), num_cols(0), data(NULL) {};
// constructor with size
utlMatrix(int, int);
// destructor
~utlMatrix();
// copy constructor
utlMatrix(const utlMatrix&);
void copy(const utlMatrix &old); // copy 'old' to 'this'
void zero(); // sets all values to zero
void fill_rand(); //fills the data with random stuff
void print(std::ostream&); // prints the matrix to a file
// Operators
utlMatrix& operator=(const utlMatrix&); // copies matrices
friend utlMatrix operator+(const utlMatrix&, const utlMatrix&); // adds 2 matrices
utlMatrix operator*(const utlMatrix&) const;
//friend utlMatrix operator*(const utlMatrix&, const utlMatrix&); // multiplies 2 matrices
};
コンストラクタ、代入演算子、およびデストラクタのコピー
// copy constructor
utlMatrix::utlMatrix(const utlMatrix &old) {
copy(old);
}
utlMatrix& utlMatrix::operator=(const utlMatrix &old) {
copy(old);
return *this;
}
void utlMatrix::copy(const utlMatrix &old) {
num_rows = old.num_rows;
num_cols = old.num_cols;
data = new float*[num_rows];
for (int i = 0; i < num_cols; i++)
data[i] = new float[num_cols];
for (int i = 0; i < num_rows; i++)
{
for (int j = 0; j < num_cols; j++)
data[i][j] = old.data[i][j];
}
}
utlMatrix::~utlMatrix()
{
for (int i = 0; i < num_rows; i++)
delete [] data[i];
delete [] data;
}
乗算演算子、両方を試しましたが、2 回続けて使用すると両方とも失敗しました。
/*
utlMatrix operator*(const utlMatrix &left, const utlMatrix &right)
{
// first determine if the matrices can be multiplied
if (left.num_cols != right.num_rows)
{
std::cout << "Error using *, Inner dimensions must agree." << std::endl;
exit(-1);
}
// create the new matrix
utlMatrix newmat(left.num_rows, right.num_cols);
for (int i = 0; i < left.num_rows; i++)
for (int j = 0; j < right.num_cols; j++)
for (int k = 0; k < right.num_rows; k++)
newmat.data[i][j] += left.data[i][k] * right.data[k][j];
return newmat;
}
*/
utlMatrix utlMatrix::operator*(const utlMatrix &right) const
{
if ( this->num_cols != right.num_rows)
{
std::cout << "Error using *, Inner dimensions must agree." << std::endl;
return utlMatrix();
}
utlMatrix newmat(this->num_rows, right.num_cols);
for (int i = 0; i < this->num_rows; i++)
for (int j = 0; j < right.num_cols; j++)
for (int k = 0; k < right.num_rows; k++)
newmat.data[i][j] += this->data[i][k] * right.data[k][j];
return newmat;
}
コピー コンストラクター、代入演算子、および加算演算子はすべて正常に機能します。ある行列を別の行列で乗算しようとすると、最初は機能しますが、2 回目は失敗します。乗算後に行列を出力することに加えて、コンストラクタ、演算子、およびデストラクタに入ったときにコードを書き出すようにコードを変更しました。数学は最初の行列に適していて、コードは次のように失敗します。
Unhandled exception at 0x776015de in sandbox.exe: 0xC0000005: Access violation writing location 0xcdcdcdcd.
画面出力から、これは 2 番目の乗算に続いてコピー コンストラクターが呼び出された後に発生していることがわかります。加算演算子は最初の乗算演算子をミラーリングし、正常に動作するように見えます。例外はなく、コピー コンストラクターとデストラクターは期待どおりに発生します。SO、 Matrix class operator overloading、destructor problem、Matrix Multiplication with operator overloadingに関する 2 つの回答が見つかりました。ポインターがコピーされていないことを確認しました。コピー コンストラクターは、データへの新しいポインターを使用して新しいオブジェクトを作成します。私が実行した場合:
int main()
{
utlMatrix A(3,3);
utlMatrix B(2,2);
A.fill_rand();
B.fill_rand();
B = A;
return 0;
}
デバッガーには次のように表示されます。
A {num_rows=3 num_cols=3 data=0x000365c0 ...} utlMatrix
B {num_rows=3 num_cols=3 data=0x00037c50 ...} utlMatrix
私は何を取りこぼしたか?実際にオペレーターを使ってみた様子です。D = A * B の後に障害が発生します。
#include "utlMatrix.h"
int main()
{
// create the first matrices
utlMatrix A(3,3);
utlMatrix B(3,3);
utlMatrix C(3,2);
// fill them with random numbers
A.fill_rand();
B.fill_rand();
C.fill_rand();
utlMatrix D = A * B;
utlMatrix E = A * C;
utlMatrix F = B * C;
}