如何正确管理内存(运行时)C++



所以我有一个名为MatrixMxN的类,在构造函数中它有参数行、列。我正试图为一个维度为行、列的2D数组分配内存,尽管这样做会遇到问题。。(我覆盖括号运算符为每个条目赋值)

{
    MatrixMxN coord(4, 1);
    coord(0, 0) = 1.0;
    coord(0, 1) = 1.0;
    coord(0, 2) = 1.0;
    coord(0, 3) = 1.0;
}

我面临的问题似乎是当解构器被调用时,我收到错误:-

Windows在MatrixTest.exe中触发了一个断点。这可能是由于堆损坏,这表明MatrixTest.exe或其加载的任何DLL中存在错误。

我的矩阵类中的片段如下所示;

typedef float* floatPtr;
class MatrixMxN {
private:
    float** entry;
    int rows;
    int cols;
public:
    MatrixMxN(int r, int c) {
        rows = r;
        cols = c;
        //Create a matrix
        if(rows > 0 && cols > 0) {
            //Declare an array of pointers
            entry = new floatPtr[rows];
            //Declare each array
            for(int i=0; i<rows; i++) {
                entry[i] = new float[cols];
            }
            this->empty();
        }
    }
    ~MatrixMxN() {
        //Free memory
        for(int i=0; i<rows; i++) {
            delete[] entry[i];
        }
        //Free pointers array
        delete[] entry;
    }
    void empty() {
        for(int i=0; i<rows; i++) {
            for(int j=0; j<cols; j++) {
                entry[i][j] = 0;
            }
        }
    }
    // Assignment operator
    void operator=(MatrixMxN& other) {
        //Check they are the same size
        assert(rows == other.rows && cols == other.cols);
        //Copy
        for(int i=0; i<rows; i++) {
            for(int j=0; j<cols; j++) {
                entry[i][j] = other(i, j);
            }
        }
    }
    float& operator()(const int irow, const int icol) {
        //Check they are not out of bounds
        assert ( (irow >= 0 && irow < rows) ||  (icol >= 0 && icol < cols) );
        return entry[irow][icol];
    }
...

引起错误的部分在循环内部的解构器中;

    //Free memory
    for(int i=0; i<rows; i++) {
        delete[] entry[i];
    }

dbgheap.c文件在第一次尝试删除[]条目[i]时抛出错误,其中i=0。虽然在打印矩阵时,它可以正常工作,但这里似乎有一个错误。希望我在这里提供了足够的信息,谢谢。

第1版:包含赋值运算符重载第2版:包含()过载

答案:问题是我是以转置的方式输入值的,而不是我如何输入的。这里的内存被破坏了,谢谢你的帮助。

您应该在一个步骤中分配内存:分配一个M*N个浮点数组,然后计算每次访问的访问位置。您的解除分配也同样简单:删除[]矩阵;

您的类可能会泄漏内存并具有未定义的行为

你有一个巨大而邪恶的错误:你错过了一个合适的复制构造函数。编译器将为您生成一个执行正确操作的程序:复制指针。但这不是你想要的;相反,复制构造函数应该分配新内存并复制数组的内容。

换句话说:使用当前的实现,您很容易泄漏内存并进行双重删除。

选择:

  • 阅读"三条规则"
  • 使用标准容器(std::vector),这些容器具有定义良好的复制语义,并自己管理内存。当您所拥有的只是标准容器时,您甚至根本不需要析构函数、复制构造函数和复制赋值(如果您不以多态方式删除矩阵类)

此外,还有一条风格建议:不要这样使用empty。所有标准容器都有一个empty()方法,它的作用与您的完全不同。

这可能不是原因,但没有为类MatrixMxN定义复制构造函数或赋值运算符:要么定义它们,要么通过声明它们private使对象不可复制。

虽然本例中没有问题,但如果是rows > 0而不是cols <= 0,则会在析构函数中未初始化的指针上调用delete[]。在构造函数中,entry仅在rows > 0 && cols > 0的情况下初始化。如果rows > 0而不是cols <= 0,则析构函数中的以下for循环仍然调用delete[] entry[i];:

for(int i=0; i<rows; i++) {
    delete[] entry[i]; // entry unitialized
}

然后是:

delete[] entry; // entry unitialized

编辑:

operator()中的assert不正确:

assert ( (irow >= 0 && irow < rows) ||  (icol >= 0 && icol < cols) );

它应该使用&&:

assert ( (irow >= 0 && irow < rows) &&  (icol >= 0 && icol < cols) );

您的empty()方法正在遍历行和行,而不是行和列。这会损坏内存,当您删除条目时,内存会被捕获。

当你分配元素时,你也可能会破坏内存,因为在你的例子中,你的索引似乎是转置的:

coord(0, 0) = 1.0;
coord(0, 1) = 1.0;
coord(0, 2) = 1.0;
coord(0, 3) = 1.0;

你的意思不是:

coord(0, 0) = 1.0;
coord(1, 0) = 1.0;
coord(2, 0) = 1.0;
coord(3, 0) = 1.0;

最新更新