【Heremei】 问题解决 - 写矩阵运算的时候遇到的问题(指针,类)
https://www.luogu.com.cn/discuss/show/337736?page=2
简单说
- 拷贝构造函数只会在新建对象的时候被调用,已经定义过的对象没法用到拷贝构造函数。
- =调用的是=的函数,不是拷贝构造函数(和上一条相关联)
- 删除一个没有赋过值的指针,会出错
- C++的函数内部如果声明并初始化了一个类的对象,并且在函数结束的时候要将这个对象返回,则实际的执行机制是首先调用该类的拷贝构造函数生成一个该对象的拷贝,然后返回这个拷贝,然后原始的对象会被析构。我之前一个以为是直接返回函数内部定义的变量,因此在这个过程中拷贝构造函数就显得十分重要,编译器会为我们生成一个默认的拷贝构造函数,但是当对象的类中含有指针成员的时候,这个默认的拷贝构造函数是错误的,不可能满足我们的要求,这时就要自己实现拷贝构造函数。(来自https://blog.csdn.net/jinxi1978/article/details/105578085/)(博主的“我以为”也是我以为的……)
事情经过
以下是原程序
#include<iostream>
using namespace std;
class Matrix{
public:
int row,col;
int **mat;
Matrix(int n,int m){
this->row=n,this->col=m;
this->mat=new int*[n+1];
for(int i=1;i<=n;i++){
this->mat[i]=new int[m+1];
}
}
Matrix(const Matrix &x){
for(int i=0;i<=this->row;i++){
delete[] this->mat[i];
}
delete[] mat;
this->row=x.row,this->col=x.col;
this->mat=new int*[row+1];
for(int i=1;i<=this->row;i++){
this->mat[i]=new int[col+1];
for(int j=1;j<=this->col;j++){
this->mat[i][j]=x.mat[i][j];
}
}
}
~Matrix(){
for(int i=0;i<=this->row;i++){
delete[] this->mat[i];
}
delete[] mat;
}
Matrix operator+(const Matrix& x) const{
if(x.row!=this->row||x.col!=this->col){
return *this;
}
Matrix c(x.row,x.col);
for(int i=1;i<=this->row;i++){
for(int j=1;j<=this->col;j++){
c.mat[i][j]=this->mat[i][j]+x.mat[i][j];
}
}
c.printMat();
return c;
}
// void left_time(Matrix *x){
//
// }
void printMat(){
for(int i=1;i<=this->row;i++){
for(int j=1;j<=this->col;j++){
cout<<this->mat[i][j]<<' ';
}
cout<<'\n';
}
}
};
int main(){
Matrix mat1(3,3),mat2(4,3);
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
cin>>mat1.mat[i][j];
}
}
Matrix mat3(3,2);
mat2=mat1;
mat3=mat1;
Matrix mat4(3,3);
mat3+mat2;
mat2.printMat();
return 0;
}
在mat3+mat2这里,调用+重载的时候,return时出错。现象为卡在那里,很快终止程序(不会跳提示框),返回值不是0,会出现很奇怪的错误。这大概就是内存出问题了……
想半天没想明白,有位dalao(感谢万分)重写了代码
class Matrix {
public:
int row;
int col;
int** mat;
Matrix(int n, int m) {
this->row = n;
this->col = m;
this->mat = new int*[n + 1];
for (int i = 1; i <= n; i++)
this->mat[i] = new int[m + 1];
}
Matrix(const Matrix& x) {
this->row = x.row;
this->col = x.col;
this->mat = new int*[row + 1];
for (int i = 1; i <= this->row; i++) {
this->mat[i] = new int[col + 1];
for (int j = 1; j <= this->col; j++)
this->mat[i][j] = x.mat[i][j];
}
}
Matrix& operator=(const Matrix& other) {
Matrix tmp(other);
swap(*this, tmp);
return *this;
}
~Matrix() {
for (int i = 1; i <= this->row; i++)
delete[] this->mat[i];
delete[] mat;
}
Matrix operator+(const Matrix& x) const {
if (x.row != this->row || x.col != this->col)
return *this;
Matrix c(x.row, x.col);
for (int i = 1; i <= this->row; i++)
for (int j = 1; j <= this->col; j++)
c.mat[i][j] = this->mat[i][j] + x.mat[i][j];
c.printMat();
return c;
}
void printMat() {
for (int i = 1; i <= this->row; i++) {
for (int j = 1; j <= this->col; j++)
std::cout << this->mat[i][j] << ' ';
std::cout << '\n';
}
}
friend void swap(Matrix& a, Matrix& b) {
using std::swap;
swap(a.row, b.row);
swap(a.col, b.col);
swap(a.mat, b.mat);
}
};
这个程序是正确的。但是没有修改+重载和构造函数,只修改了拷贝构造,然后加了=的重载。
当我把主程序换成这个:
int main(){
Matrix mat1(3,3),mat2(4,3),mat3(4,3);mat2;
return 0;
}
原程序依然会错……而这根本不涉及正确程序所改动的东西。
为什么呢?原来是因为在return的时候,程序会自动调用拷贝构造创建一个新的对象返回,然后调用析构函数销毁函数里的临时对象!
https://blog.csdn.net/jinxi1978/article/details/105578085/
而在拷贝构造的时候我写了这个语句:
for(int i=1;i<=this->row;i++){
delete[] this->mat[i];
}
delete[] mat;
虽然for循环不会被调用,但是底下的那条依旧被调用了……但是mat现在没有指向一块新空间,还是默认的(我试了试是00x1c),所以要删掉它就出错了。
确实是这样,运行+的时候,在拷贝构造for循环上面写一个输出,就会输出,这说明确确实实调用了拷贝构造,而在delete[] mat后写的输出代码就会卡住运行不了。
当初之所以这么写是因为以为=是自动调用的拷贝构造函数实现的,结果不是……所以当时的我想着万一等号左边的对象里有数据,这样那些空间不被释放,就会一直积累然后内存一直被占用……
事实上拷贝构造只会在新建对象的时候被调用。
内容可以为空
浙公网安备 33010602011771号