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

时间:2012-03-26 12:56:44

标签: c++ debugging memory

所以我有一个名为MatrixMxN的类,在构造函数中它有参数row,column。我正在尝试为尺寸为row,column的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文件在第一次尝试删除[] entry [i]时抛出错误,其中i = 0。虽然在打印矩阵时它按预期工作正常,但这里似乎有错误。希望我在这里提供了足够的信息,谢谢。

Edit1:包含赋值运算符重载 Edit2:Included()重载

答案: 问题是我是以转置的方式输入值而不是我的方式。感谢所有帮助,记忆在这里被破坏了。

4 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:3)

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

你有一个大而邪恶的错误:你错过了一个合适的拷贝构造函数。编译器将为您生成一个正确的东西:复制指针。但那不是你想要的;相反,您的复制构造函数应分配新内存并复制数组的内容。

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

选择:

  • 请阅读The Rule of Three
  • 使用标准容器(std::vector),它们具有良好定义的复制语义并自行管理其内存。当你拥有的只是标准容器时,你甚至根本不需要析构函数和复制构造函数和复制赋值(如果你不以多态方式删除矩阵类)

另外,风格建议:不要像这样使用empty。所有标准容器都有一个empty()方法,它可以完全不同于您的方法。

答案 2 :(得分:2)

你的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;

答案 3 :(得分:2)

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

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

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

接下来是:

delete[] entry; // entry unitialized

编辑:

assert中的operator()不正确:

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

它应该使用&&

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