析构函数立即调用并删除我的数组

Destructor immediately calls and deletes my arrays

本文关键字:删除 我的 数组 调用 析构函数      更新时间:2023-10-16

我正在为一个CS项目开发一个矩阵类,我正在尝试处理构造函数。该项目调用两个不同的构造函数,一个只是调用行数和列数并使它们全部为 0,另一个使用初始值设定项列表来分配值。到目前为止,头文件是:

typedef unsigned int uint;
typedef std::initializer_list<std::initializer_list<double>> i_list;
class Matrix {
public:
double ** arr;
uint mainRows;
uint mainCols;
Matrix(uint rows, uint cols);
Matrix(const i_list & list);
Matrix(const Matrix & m);
~Matrix();
};

某些测试用例要求您定义行并使用初始值设定项列表,例如:

Matrix d(2,2);
d = {{1,2},{3,4}};

但我注意到,每次我尝试运行这种代码时,析构函数都会立即删除双 ** arr,这是存储矩阵值的位置。下面是构造函数的代码:

    Matrix::Matrix(uint rows, uint cols)
{
    mainRows = rows;
    mainCols = cols;
    arr = new double*[rows];
    for (int i = 0; i < mainRows; i++) {
        arr[i] = new double[cols];
    }
    for (int i = 0; i < mainRows; i++) {
        for (int j = 0; j < mainCols; j++) {
            arr[i][j] = 0;
        }
    }
}
Matrix::Matrix(const i_list & list)
{
    int i = 0, j = 0;
    mainRows = list.size();
    mainCols = (*list.begin()).size();
    arr = new double*[mainRows];
    for (std::initializer_list<double> I : list) {
        j = 0;
        arr[i] = new double[mainCols];
        for (double d : I) {
            arr[i][j] = d;
            j++;
        }
        i++;
    }
}
Matrix::Matrix(const Matrix & m)
{
    this->arr = m.arr;
    this->mainRows = m.mainRows;
    this->mainCols = m.mainCols;
    for (uint i = 0; i < mainRows; i++) {
        for (uint j = 0; j < mainCols; j++) {
            this->arr[i][j] = m.arr[i][j];
        }
    }
}
Matrix::~Matrix()
{
    for (uint i = 0; i < mainRows; i++) {
        delete[] arr[i];
    }
    delete[] arr; 
}

我想因为它为同一个对象调用了两次构造函数,它创建了两个双 ** ar,这就是为什么析构函数想要删除原始内容的原因,但随后我无法调用其他函数的值。有人可以帮助我解决我做错的事情吗?

问题是复制构造函数只复制源对象的指针,而不分配新内存。

这是有问题的,因为

d = {{1,2},{3,4}};

{{1,2},{3,4}}创建一个临时对象。你的说法实际上等于

d = Matrix({{1,2},{3,4}});

等于

d.operator=(Matrix({{1,2},{3,4}}));

完成分配后,您有两个对象指向同一内存以进行arr。然后临时对象被破坏,导致d内部的arr变得无效,因为它不再指向分配的内存。

简单的解决方案很简单:为复制构造函数中指向arr分配内存。更好的解决方案是停止使用指针和动态分配,而是使用 std::vector ,并遵循零规则,其中不需要任何复制构造函数、复制赋值运算符和析构函数。

这是

错误的:

Matrix::Matrix(const Matrix & m)
{
    this->arr = m.arr;
    this->mainRows = m.mainRows;
    this->mainCols = m.mainCols;
    for (uint i = 0; i < mainRows; i++) {
        for (uint j = 0; j < mainCols; j++) {
            this->arr[i][j] = m.arr[i][j];
        }
    }
}

请注意,您不会在此处创建实际副本。 this->arr = m.arr;使两个指针指向内存的同一部分,因此Matrix的新旧实例共享此内存。因此,流动for循环无济于事。

当其中一个实例被销毁时,另一个实例指向释放的内存。