程序按执行方式工作,直到我向其添加析构函数为止

program works as excpected untill I add a destructor to it

本文关键字:添加 析构函数 执行 方式 工作 程序      更新时间:2023-10-16
#include <iostream>
using namespace std;
class Matrix {
public:
long int **Matr;
long int n;
void Create() {
Matr = new long int *[n];
for (int z = 0; z < n; z++)
Matr[z] = new long int[n];
}
// constructors and destructor
Matrix() : n(5) { Create(); }
Matrix(long int i) : n(i) { Create(); }
// Copy constructor
Matrix(Matrix &N) {
n = N.n;
Matr = new long int *[n];
for (int i = 0; i < n; i++)
Matr[i] = new long int[n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
Matr[i][j] = N.Matr[i][j];
}
}
}
Matrix operator*(Matrix &mx) {
int i, j, k, num;
Matrix result(n);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
num = 0;
for (int k = 0; k < n; k++) {
num += Matr[i][k] * mx.Matr[k][j];
}
result.Matr[i][j] = num;
return result;
}
~Matrix() {
for (int z = 0; z < n; z++) {
delete[] Matr[z];
}
delete[] Matr;
}
void Display() {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cout << Matr[i][j];
}
cout << endl;
}
}
Matrix operator+(Matrix &mx) {
Matrix result(n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
result.Matr[i][j] = Matr[i][j] + mx.Matr[i][j];
// cout << result.Matr[i][j] << "n";
}
}
return result;
}
};
int main() {
Matrix M(2);
M.Matr[0][0] = 0;
M.Matr[0][1] = 1;
M.Matr[1][0] = 2;
M.Matr[1][1] = 3;
Matrix N(2);
N.Matr[0][0] = 0;
N.Matr[0][1] = 1;
N.Matr[1][0] = 2;
N.Matr[1][1] = 3;
Matrix C;
C = M + N;
cout << C.Matr[0][0];
return 0;
}

我正在用一些基本方法做一个矩阵 OOP 类。我不能按照我想要的方式做"+"运算符工作。在这种情况下,当我尝试打印 C.Matr[0][0] 时,出于某种原因它正在打印随机数,但如果我只是从代码中删除析构函数,它会按预期工作并打印 0。有人可以帮助我弄清楚为什么会发生这种情况吗?多谢。

C被分配了一个具有共享Matr的临时 。临时指针会立即死亡,您会删除 dtor 中的悬空指针。

三/五/零规则将帮助您防止它。


您缺少复制赋值运算符的内容:

Matrix& operator=(const Matrix& N)
{
// copy to temporary matrix
long int tmpN = N.n;
long int** tmpMatr = new long int*[tmpN];
for (int i = 0; i < tmpN; i++)
tmpMatr[i] = new long int[tmpN];
for (int i = 0; i < tmpN; i++)
{
for (int j = 0; j < tmpN; j++)
tmpMatr[i][j] = N.Matr[i][j];
}
// swap
long int** swapMatr = Matr;
long int swapN = n;
Matr = tmpMatr;
n = N.n;
// deallocate old Matr
for (int z = 0; z<swapN; z++){
delete[] swapMatr[z];
}  
delete[] swapMatr;
return *this;
}

在线 gdb

必须实现赋值运算符,而不仅仅是复制构造函数和析构函数。

实现赋值运算符的最简单方法是使用复制/交换习惯用法:

#include <algorithm>
//...
class Matrix
{
//...
int **Matr;
int n;
//...
public:
Matrix& operator=(const Matrix& m)
{
if ( this != &m )
{
Matrix temp(m);  // create a copy of the passed in value
std::swap(temp.Matr, Matr);  // swap out the internals with *this
std::swap(temp.n, n);
}  // Here temp's destructor removes the old memory that *this 
// previously had
return *this;
}
//...
};

请注意,这仅在您有一个有效的、没有错误的复制构造函数和析构函数时才有效。

此外,您的复制构造函数应该采用const引用,而不仅仅是对Matrix的引用:

Matrix(const Matrix& m) { ... }

进行这些更改后,程序将不再崩溃,如下所示。

您没有赋值运算符,所以谁知道C = M + N;行在做什么?

好吧,它使用默认的赋值运算符,它只是依次复制每个成员。特别是,指针Matr是从临时M+N中的指针复制的,因此它指向分配给临时的内存,然后被销毁。

在添加析构函数之前,您遇到了内存泄漏,因此值保留在堆中,并且它似乎有效。添加释放内存的析构函数后,它显然很快被覆盖。