【发布时间】:2020-10-03 18:10:08
【问题描述】:
我目前正在从事一个更大的项目,其中涉及实现线性代数计算器。我决定不使用任何其他可能帮助我实现它的现有库,因为我认为这太容易了。
我首先开始编写 Matrix 类,现在看起来像这样:
class Matrix{
private:
int rows; // no. rows
int columns; // no. columns
double** matVal; //values of the matrix
char name; //only used when printing it out or by outside programs.
public:
//constructors and destructor
Matrix();
Matrix(int r,int c,char _name);
~Matrix();
//basic get functions for private access
int getNrRows();
int getNrCols();
char getName();
double getVal(int row,int col);
//basic set functions for private variables
void setVal(int row,int col,double value);
void setName(char _name);
//basic matrix operations
Matrix operator=(Matrix M);
Matrix operator+(Matrix M);
Matrix operator-(Matrix M);
Matrix operator*(Matrix M);
//Printing out the matrix
void Print();
};
一开始很顺利,但后来我偶然发现了一个致命的错误,这不会让我进一步进步。有关更多信息,这里是我的函数(+ 一些试图找出问题所在的代码)以及我在 main() 中执行的内容:
#define cout std::cout
Matrix::Matrix(){
rows = 0;
columns = 0;
matVal = nullptr;
}
Matrix::Matrix(int r,int c,char _name){
rows = r;
columns = c;
name = _name;
matVal = new double*[r];
for(int i = 0; i < r; i++){
matVal[i] = new double[c];
}
for(int i = 0; i < r; i++){
for(int j = 0; j < c; j++){
matVal[i][j] = 0;
}
}
}
Matrix::~Matrix(){
for (int i = 0; i < rows; i++)
delete[] matVal[i];
delete[] matVal;
}
int Matrix::getNrRows(){
return rows;
}
int Matrix::getNrCols(){
return columns;
}
char Matrix::getName(){
return name;
}
double Matrix::getVal(int row, int col){
return matVal[row-1][col-1];
}
void Matrix::setVal(int row,int col,double value){
matVal[row-1][col-1] = value;
}
void Matrix::setName(char _name){
name = _name;
}
Matrix Matrix::operator=(Matrix M){
for (int i = 0; i < rows; i++)
delete[] matVal[i];
delete[] matVal;
rows = M.rows;
columns = M.columns;
matVal = new double*[rows];
for(int i = 0; i < rows; i++){
matVal[i] = new double[M.columns];
}
for(int i = 0; i < M.rows; i++){
for(int j = 0; j < M.columns; j++){
matVal[i][j] = M.matVal[i][j];
cout<<matVal[i][j]<<' ';
}
cout<<'\n';
}
cout<<this<<std::endl;
return *this;
}
Matrix Matrix::operator+(Matrix M){
Matrix Rez;
Rez.rows = rows;
Rez.columns = columns;
for(int i = 0; i < rows; i++){
for(int j = 0; j < columns; j++){
Rez.matVal[i][j] = matVal[i][j] + M.matVal[i][j];
}
}
return Rez;
}
void Matrix::Print(){
cout<<'\n';
cout<<name<<": "<<"\n";
for(int i = 0; i < rows; i++){
for(int j = 0; j < columns; j++){
cout<<matVal[i][j]<<' ';
}
cout<<'\n';
}
cout<<'\n';
return;
}
主要:
Matrix M(4,3,'A');
M.setVal(1,1,2);
M.setVal(1,3,-1.1);
M.Print();
Matrix A(4,3,'B');
A.setVal(3,2,5);
A.Print();
Matrix C(4,3,'C');
C = A;
cout<<C.getVal(3,2)<<'\n';
cout<<C.getNrCols()<<" "<<C.getNrRows()<<endl;
C.Print();
cout<<"S"<<endl;
打印前 2 个矩阵工作正常,当我在给它分配了正确的值之后在 operator= 函数中打印 C 的每个元素时,它再次工作正常,但是当我在 C 上使用 Print() 函数时它崩溃.这是上面代码的控制台输出:
A:
2 0 -1.1
0 0 0
0 0 0
0 0 0
B:
0 0 0
0 0 0
0 5 0
0 0 0
0 0 0
0 0 0
0 5 0
0 0 0
0x69fed0
5
3 4
C:
一开始我完全不知道为什么会这样,但后来我打印了指向每个变量的指针(它全部打印出来,这次返回 0):
A:
0x850e38 0x850e40 0x850e48
0x851318 0x851320 0x851328
0x851338 0x851340 0x851348
0x851358 0x851360 0x851368
B:
0x851390 0x851398 0x8513a0
0x8513b0 0x8513b8 0x8513c0
0x8513d0 0x8513d8 0x8513e0
0x855b08 0x855b10 0x855b18
0x855b40 0x855b48 0x855b50
0x855b60 0x855b68 0x855b70
0x855b80 0x855b88 0x855b90
0x855ba0 0x855ba8 0x855bb0
0x69fed0
5
3 4
C:
0 0x8 0x10
0 0x8 0x10
0 0x8 0x10
0 0x8 0x10
S
现在我认为 Print 函数有问题(否则为什么我能够在 main 中打印出 5?)。我仍然不知道到底发生了什么,所以我请求你的帮助。如果这是菜鸟的错误,我很抱歉,我还很缺乏经验。
我还忘了补充一点,类和类函数位于不同的文件(头文件和 cpp)中,虽然我不知道这会如何影响事情。
【问题讨论】:
-
您应该检查是否 (this != &M) in operator= 重载,因为您将使用同一个对象执行所有操作
-
另外,查找“三规则”。要点是,如果需要手动定义赋值运算符、复制构造函数或析构函数之一,则有必要实现所有这三个。您已经实现了赋值运算符和析构函数,但没有实现复制构造函数。在 C++11 及更高版本中,三法则变为五法则。当复制管理资源的对象(例如,在您的情况下动态分配的内存)时,不遵循这些规则最终会产生未定义的行为。
-
@Marius,如果您在向其添加
*this后返回相同的值,则按值传递就可以了。另请注意,operator=应该通过引用返回*this,或者如果不需要链接分配,则只是void。 -
当您通过值传递
Matrix时,副本包含与原始相同的指针。当副本超出范围时,析构函数将delete[]那些指针。因此,您会在原始Matrix中获得悬空指针,并且这些指针是双倍的。
标签: c++ class pointers matrix dynamic-memory-allocation