赋值运算符 (=) 与矩阵 returns 垃圾值
Assignment operator (=) with matrices returns garbage values
我正在用 C++ 构建 class "Matrix",但在创建 operator= 时遇到了一些问题。
下面提供了实现,然后是不起作用的代码,但让我澄清一下问题,因为它相当具体:
创建两个新矩阵 m1,m2 后,操作 m1=m2 将 m1 设置为包含垃圾值。
话虽如此,在 operator= 的范围内,我正在处理的 "this" 矩阵似乎拥有正确的值。
从 operator=(right-hand side) 返回值到实际将其分配给左侧 m1
的路径有问题
话又说回来,这里是整个文件,但具体来说,请注意 operator= 以及可能是构造函数 - 我认为这是导致问题的原因。
h-文件
// Matrix.h
#ifndef MATRIX_H
#define MATRIX_H
#include <fstream>
#include <iostream>
class Matrix
{
public:
Matrix(int rows, int cols); //ctor
Matrix(); //default ctor
Matrix(const Matrix &m); // copy ctor
~Matrix(); //destructor
int getRows() const;
int getCols() const;
Matrix &vectorize(); // convert matrix to vector
void plainPrint() const; // print matrix
Matrix &operator=(const Matrix &b); // assignment this = b
Matrix &operator*(float c); // M*c
friend Matrix &operator*(float c, Matrix &m); // c*M
friend Matrix operator+(const Matrix &a, const Matrix &b); //a+b
friend Matrix operator*(const Matrix &a, const Matrix &b); // a*b
Matrix &operator+=(const Matrix &b); //this += b
float& operator()(int i, int j); // this(i,j)
float& operator[](int i); // this[i]
float& operator()(int i, int j) const; //const this(i,j)
float& operator[](int i) const; //const this[i]
friend std::ostream &operator<<(std::ostream &os, const Matrix &m);
friend std::istream &operator>>(std::istream &is, const Matrix &m);
private:
int _rows, _cols;
float *_mat;
static void throwError();
static float getSum(const Matrix &a, const Matrix &b, int k, int i, int j);
};
#endif //MATRIX_H
cpp 文件
#include "Matrix.h"
#include <string>
#include <iostream>
using std::string;
using std::cerr;
using std::endl;
using std::cout;
using std::cin;
#define ERR_MSG "program failed - you've probably done something wrong."
#define INITIAL_SIZE 1
/** ------------------------------------ private functions ------------------------------------**/
/**
* prints an error message to cerr and exists with exit failure code
*/
void Matrix::throwError()
{
cerr << ERR_MSG << endl;
exit(EXIT_FAILURE);
}
/**
* * used for matrices multiplication. returns the value of c_ij according to
* c_ij = a_ik * b_kj , where k is a summation index
* @param a - some matrix
* @param b - some matrix
* @param k - amount to sum
* @param i - current row
* @param j -current column
* @return c_ij as specified
*/
float Matrix::getSum(const Matrix &a, const Matrix &b, int k,int i,int j)
{
float c_ij = 0;
for (int l = 0; l < k ; l++)
{
c_ij+=a.operator()(i,l)*b.operator()(l,j);
}
return c_ij;
}
/** ------------------------------------ constructors ------------------------------------**/
/**
* constructor for martix instance, initializes all matrix values to zero
* @param rows - number of rows
* @param cols - number of columns
*/
Matrix::Matrix(int rows, int cols) :
_rows(rows), _cols(cols), _mat(nullptr)
{
if (rows <= 0 || cols <= 0) // checking valid input
{
throwError();
}
_mat = new(std::nothrow) float[rows * cols]; // allocating memory
if (_mat == nullptr)
{
throwError();
}
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
_mat[i * cols + j] = 0;
}
}
}
/**
*default constructor - initializes a matrix of size 1x1
*/
Matrix::Matrix() : Matrix(INITIAL_SIZE, INITIAL_SIZE)
{}
/**
* copy constructor
* @param m some matrix
*/
Matrix::Matrix(const Matrix &m) : Matrix(m._rows,m._cols)
{
*this = m;
}
/**
* destructor for class Matrix - frees _mat from memory
*/
Matrix::~Matrix()
{
delete[] _mat;
_mat = nullptr;
}
/** ------------------------------------ methods ------------------------------------**/
/**
* @return amount of rows as int
*/
int Matrix::getRows() const
{
return _rows;
}
/**
* @return amount of columns as int
*/
int Matrix::getCols() const
{
return _cols;
}
/**
* converts a matrix into a column vector
* @return
*/
Matrix &Matrix::vectorize()
{
int newCols = INITIAL_SIZE; // 1 column
int newRows = _cols * _rows;
_rows = newRows;
_cols = newCols;
return *this;
}
void Matrix::plainPrint() const
{
cout << endl;
for (int i = 0; i < _rows; i++)
{
for (int j = 0; j < _cols; j++)
{
cout << _mat[i * _cols + j] << " ";
}
cout << endl;
}
}
/** ------------------------------------ operators ------------------------------------**/
Matrix &Matrix::operator=(const Matrix &b)
{
if (this!=&b) // b is not this
{
delete[] _mat;
_mat = nullptr;
float newValues[b._rows * b._cols];
for (int i = 0; i < b._rows * b._cols; i++)
{
newValues[i] = b._mat[i];
}
_mat = newValues;
_rows = b._rows;
_cols = b._cols;
}
return *this;
}
/**
* returns this matrix multiplied by c
* notice that this is a member function, performed on this matrix
* @param c - some value
* @return M*c
*/
Matrix &Matrix::operator*(float c)
{
for (int i = 0; i < _rows; i++)
{
for (int j = 0; j < _cols; j++)
{
_mat[i * _cols + j] *= c;
}
}
return *this;
}
/**
* returns c*M. notice this is not a member function (does not operates on this matrix)
* @param c - some value
* @param m - some matrix
* @return
*/
Matrix &operator*(float c, Matrix &m)
{
for (int i = 0; i < m._rows; i++)
{
for (int j = 0; j < m._cols; j++)
{
m._mat[i * m._rows + j] = m._mat[i * m._rows + j] * c;
}
}
return m;
}
/**
* adds two matrices together
* @param a some matrix
* @param b some matrix
* @return a+b
*/
Matrix operator+(const Matrix &a, const Matrix &b)
{
if (a._rows != b._rows || a._cols != b._cols)
{
a.throwError(); // matrices must be of same dimension
}
int rows = a._rows;
int cols = a._cols;
Matrix newMat = Matrix(rows, cols);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
newMat._mat[i * cols + j] = a._mat[i * cols + j] + b._mat[i * cols + j];
}
}
return newMat;
}
/**
* multiplies two matrices
* @param a - some matrix (must be m*n)
* @param b - some matrix (must be n*p)
* @return new matrix a*b (m*p)
*/
Matrix operator*(const Matrix &a, const Matrix &b)
{
if(a._cols != b._rows)
{
a.throwError(); // matrices must be of dimensions a_(m * n) * b_(n * p)
}
// assigning letters to correspond the values in description:
int m = a._rows; // = c._rows
int n = a._cols; // = b._rows
int p = b._cols; // = c._cols
Matrix c = Matrix(m,p);
for(int i=0;i<m;i++)
{
for(int j=0;j<p;j++)
{
c._mat[i*p+j] = c.getSum(a,b,n,i,j);
}
}
return c;
}
Matrix &Matrix::operator+=(const Matrix &b)
{
for (int i = 0; i < _rows; i++)
{
for (int j = 0; j < _cols; j++)
{
_mat[i * _cols + j] = _mat[i * _cols + j] + b._mat[i * _cols + j];
}
}
return *this;
}
float &Matrix::operator()(int i, int j)
{
return _mat[i * _cols + j];
}
float &Matrix::operator[](int i)
{
return _mat[i];
}
float &Matrix::operator()(int i, int j) const
{
return _mat[i * _cols + j];
}
float &Matrix::operator[](int i) const
{
return _mat[i];
}
/**
* << operator, as specified in part 3.4 of the exercise
* prints the quessed number to the screen
* @param os output stream
* @param m matrix
* @return os
*/
std::ostream &operator<<(std::ostream &os, const Matrix &m)
{
int rows = m._rows;
int cols = m._cols;
cout<<endl;
for (int i=0; i<rows-1;i++)
{
for(int j=0;j<cols-1;j++)
{
if (m.operator()(i,j)<=0.1f)
{
cout << " ";
}
else
{
cout << "**";
}
}
cout<<endl;
}
return os;
}
/**
* >> operator, reads the input and inserts it into the matrix
* @param is input stream
* @param m matrix
* @return is
*/
std::istream &operator>>(std::istream &is, const Matrix &m)
{
int rows = m._rows;
int cols = m._cols;
for (int i=0; i<rows-1;i++)
{
for(int j=0;j<cols-1;j++)
{
is.read((char*)&m[i*cols+j],sizeof(float));
if(! is.good())
{
m.throwError();
}
}
}
return is;
}
你可以试试运行这个主要看问题:
int main()
{
Matrix m1 = Matrix(4,4);
Matrix m2 = Matrix(4,4);
for(int i=0;i<16;i++)
{
m1[i]=i; //arbitrary values
m2[i]=i+2;
}
m1.plainPrint();
m2.plainPrint();
m1=m2;
m1.plainPrint();
}
这是打印的内容:
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
2 3 4 5
6 7 8 9
10 11 12 13
14 15 16 17
-nan 4.2039e-45 0 0
-3.7918e-39 0 -1.19722e+16 4.2039e-45
-nan 0 0 0
-nan 0 0 0
Process finished with exit code 0
感谢您的帮助!
你可以这样做:
Matrix& Matrix::operator=(const Matrix& b)
{
if (this != &b) // b is not this
{
delete[] _mat;
_mat = nullptr;
_mat = new float[b._rows * b._cols];
for (int i = 0; i < b._rows * b._cols; i++)
{
_mat[i] = b._mat[i];
}
_rows = b._rows;
_cols = b._cols;
}
return *this;
}
我相信这都是因为_mat = newValues;
我正在用 C++ 构建 class "Matrix",但在创建 operator= 时遇到了一些问题。 下面提供了实现,然后是不起作用的代码,但让我澄清一下问题,因为它相当具体:
创建两个新矩阵 m1,m2 后,操作 m1=m2 将 m1 设置为包含垃圾值。
话虽如此,在 operator= 的范围内,我正在处理的 "this" 矩阵似乎拥有正确的值。 从 operator=(right-hand side) 返回值到实际将其分配给左侧 m1
的路径有问题话又说回来,这里是整个文件,但具体来说,请注意 operator= 以及可能是构造函数 - 我认为这是导致问题的原因。
h-文件
// Matrix.h
#ifndef MATRIX_H
#define MATRIX_H
#include <fstream>
#include <iostream>
class Matrix
{
public:
Matrix(int rows, int cols); //ctor
Matrix(); //default ctor
Matrix(const Matrix &m); // copy ctor
~Matrix(); //destructor
int getRows() const;
int getCols() const;
Matrix &vectorize(); // convert matrix to vector
void plainPrint() const; // print matrix
Matrix &operator=(const Matrix &b); // assignment this = b
Matrix &operator*(float c); // M*c
friend Matrix &operator*(float c, Matrix &m); // c*M
friend Matrix operator+(const Matrix &a, const Matrix &b); //a+b
friend Matrix operator*(const Matrix &a, const Matrix &b); // a*b
Matrix &operator+=(const Matrix &b); //this += b
float& operator()(int i, int j); // this(i,j)
float& operator[](int i); // this[i]
float& operator()(int i, int j) const; //const this(i,j)
float& operator[](int i) const; //const this[i]
friend std::ostream &operator<<(std::ostream &os, const Matrix &m);
friend std::istream &operator>>(std::istream &is, const Matrix &m);
private:
int _rows, _cols;
float *_mat;
static void throwError();
static float getSum(const Matrix &a, const Matrix &b, int k, int i, int j);
};
#endif //MATRIX_H
cpp 文件
#include "Matrix.h"
#include <string>
#include <iostream>
using std::string;
using std::cerr;
using std::endl;
using std::cout;
using std::cin;
#define ERR_MSG "program failed - you've probably done something wrong."
#define INITIAL_SIZE 1
/** ------------------------------------ private functions ------------------------------------**/
/**
* prints an error message to cerr and exists with exit failure code
*/
void Matrix::throwError()
{
cerr << ERR_MSG << endl;
exit(EXIT_FAILURE);
}
/**
* * used for matrices multiplication. returns the value of c_ij according to
* c_ij = a_ik * b_kj , where k is a summation index
* @param a - some matrix
* @param b - some matrix
* @param k - amount to sum
* @param i - current row
* @param j -current column
* @return c_ij as specified
*/
float Matrix::getSum(const Matrix &a, const Matrix &b, int k,int i,int j)
{
float c_ij = 0;
for (int l = 0; l < k ; l++)
{
c_ij+=a.operator()(i,l)*b.operator()(l,j);
}
return c_ij;
}
/** ------------------------------------ constructors ------------------------------------**/
/**
* constructor for martix instance, initializes all matrix values to zero
* @param rows - number of rows
* @param cols - number of columns
*/
Matrix::Matrix(int rows, int cols) :
_rows(rows), _cols(cols), _mat(nullptr)
{
if (rows <= 0 || cols <= 0) // checking valid input
{
throwError();
}
_mat = new(std::nothrow) float[rows * cols]; // allocating memory
if (_mat == nullptr)
{
throwError();
}
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
_mat[i * cols + j] = 0;
}
}
}
/**
*default constructor - initializes a matrix of size 1x1
*/
Matrix::Matrix() : Matrix(INITIAL_SIZE, INITIAL_SIZE)
{}
/**
* copy constructor
* @param m some matrix
*/
Matrix::Matrix(const Matrix &m) : Matrix(m._rows,m._cols)
{
*this = m;
}
/**
* destructor for class Matrix - frees _mat from memory
*/
Matrix::~Matrix()
{
delete[] _mat;
_mat = nullptr;
}
/** ------------------------------------ methods ------------------------------------**/
/**
* @return amount of rows as int
*/
int Matrix::getRows() const
{
return _rows;
}
/**
* @return amount of columns as int
*/
int Matrix::getCols() const
{
return _cols;
}
/**
* converts a matrix into a column vector
* @return
*/
Matrix &Matrix::vectorize()
{
int newCols = INITIAL_SIZE; // 1 column
int newRows = _cols * _rows;
_rows = newRows;
_cols = newCols;
return *this;
}
void Matrix::plainPrint() const
{
cout << endl;
for (int i = 0; i < _rows; i++)
{
for (int j = 0; j < _cols; j++)
{
cout << _mat[i * _cols + j] << " ";
}
cout << endl;
}
}
/** ------------------------------------ operators ------------------------------------**/
Matrix &Matrix::operator=(const Matrix &b)
{
if (this!=&b) // b is not this
{
delete[] _mat;
_mat = nullptr;
float newValues[b._rows * b._cols];
for (int i = 0; i < b._rows * b._cols; i++)
{
newValues[i] = b._mat[i];
}
_mat = newValues;
_rows = b._rows;
_cols = b._cols;
}
return *this;
}
/**
* returns this matrix multiplied by c
* notice that this is a member function, performed on this matrix
* @param c - some value
* @return M*c
*/
Matrix &Matrix::operator*(float c)
{
for (int i = 0; i < _rows; i++)
{
for (int j = 0; j < _cols; j++)
{
_mat[i * _cols + j] *= c;
}
}
return *this;
}
/**
* returns c*M. notice this is not a member function (does not operates on this matrix)
* @param c - some value
* @param m - some matrix
* @return
*/
Matrix &operator*(float c, Matrix &m)
{
for (int i = 0; i < m._rows; i++)
{
for (int j = 0; j < m._cols; j++)
{
m._mat[i * m._rows + j] = m._mat[i * m._rows + j] * c;
}
}
return m;
}
/**
* adds two matrices together
* @param a some matrix
* @param b some matrix
* @return a+b
*/
Matrix operator+(const Matrix &a, const Matrix &b)
{
if (a._rows != b._rows || a._cols != b._cols)
{
a.throwError(); // matrices must be of same dimension
}
int rows = a._rows;
int cols = a._cols;
Matrix newMat = Matrix(rows, cols);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
newMat._mat[i * cols + j] = a._mat[i * cols + j] + b._mat[i * cols + j];
}
}
return newMat;
}
/**
* multiplies two matrices
* @param a - some matrix (must be m*n)
* @param b - some matrix (must be n*p)
* @return new matrix a*b (m*p)
*/
Matrix operator*(const Matrix &a, const Matrix &b)
{
if(a._cols != b._rows)
{
a.throwError(); // matrices must be of dimensions a_(m * n) * b_(n * p)
}
// assigning letters to correspond the values in description:
int m = a._rows; // = c._rows
int n = a._cols; // = b._rows
int p = b._cols; // = c._cols
Matrix c = Matrix(m,p);
for(int i=0;i<m;i++)
{
for(int j=0;j<p;j++)
{
c._mat[i*p+j] = c.getSum(a,b,n,i,j);
}
}
return c;
}
Matrix &Matrix::operator+=(const Matrix &b)
{
for (int i = 0; i < _rows; i++)
{
for (int j = 0; j < _cols; j++)
{
_mat[i * _cols + j] = _mat[i * _cols + j] + b._mat[i * _cols + j];
}
}
return *this;
}
float &Matrix::operator()(int i, int j)
{
return _mat[i * _cols + j];
}
float &Matrix::operator[](int i)
{
return _mat[i];
}
float &Matrix::operator()(int i, int j) const
{
return _mat[i * _cols + j];
}
float &Matrix::operator[](int i) const
{
return _mat[i];
}
/**
* << operator, as specified in part 3.4 of the exercise
* prints the quessed number to the screen
* @param os output stream
* @param m matrix
* @return os
*/
std::ostream &operator<<(std::ostream &os, const Matrix &m)
{
int rows = m._rows;
int cols = m._cols;
cout<<endl;
for (int i=0; i<rows-1;i++)
{
for(int j=0;j<cols-1;j++)
{
if (m.operator()(i,j)<=0.1f)
{
cout << " ";
}
else
{
cout << "**";
}
}
cout<<endl;
}
return os;
}
/**
* >> operator, reads the input and inserts it into the matrix
* @param is input stream
* @param m matrix
* @return is
*/
std::istream &operator>>(std::istream &is, const Matrix &m)
{
int rows = m._rows;
int cols = m._cols;
for (int i=0; i<rows-1;i++)
{
for(int j=0;j<cols-1;j++)
{
is.read((char*)&m[i*cols+j],sizeof(float));
if(! is.good())
{
m.throwError();
}
}
}
return is;
}
你可以试试运行这个主要看问题:
int main()
{
Matrix m1 = Matrix(4,4);
Matrix m2 = Matrix(4,4);
for(int i=0;i<16;i++)
{
m1[i]=i; //arbitrary values
m2[i]=i+2;
}
m1.plainPrint();
m2.plainPrint();
m1=m2;
m1.plainPrint();
}
这是打印的内容:
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
2 3 4 5
6 7 8 9
10 11 12 13
14 15 16 17
-nan 4.2039e-45 0 0
-3.7918e-39 0 -1.19722e+16 4.2039e-45
-nan 0 0 0
-nan 0 0 0
Process finished with exit code 0
感谢您的帮助!
你可以这样做:
Matrix& Matrix::operator=(const Matrix& b)
{
if (this != &b) // b is not this
{
delete[] _mat;
_mat = nullptr;
_mat = new float[b._rows * b._cols];
for (int i = 0; i < b._rows * b._cols; i++)
{
_mat[i] = b._mat[i];
}
_rows = b._rows;
_cols = b._cols;
}
return *this;
}
我相信这都是因为_mat = newValues;