简体   繁体   中英

How to properly manage memory (run-time) C++

So I have a class called MatrixMxN, in the constructor it has parameters row, column. I am attempting to allocate memory for a 2D array with dimensions row, column, although I am getting a problem with doing this.. (I am overriding the parenthesis operator to assign values to each entry)

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

The problem I am facing seems to be when the deconstructor is called and I receive the error:-

Windows has triggered a breakpoint in MatrixTest.exe. This may be due to a corruption of the heap, which indicates a bug in MatrixTest.exe or any of the DLLs it has loaded.

The snippet from my matrix class is as follows;

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];
    }
...

The part which is tripping up an error is in the deconstructor inside the loop;

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

The dbgheap.c file throws the error on the first attempt to delete[] entry[i] where i =0. Although when printing the matrix it works fine as intended but there appears to be an error here. Hopefully I have provided enough information here, thanks.

Edit1: Included assignment operator overload Edit2: Included () overload

Answer: The problem was I was entering the values in a transpose manner rather than how I had it. The memory was being corrupted here, thanks for all the help.

You should allocate the memory in one step: allocate an array of M*N floats, then calculate the access position at every access. Your deallocation would be equally simple: delete [] matrix;

Your class potentially leaks memory and has undefined behaviour

You have a big and evil mistake there: You miss a proper copy constructor. The compiler will generate one for you which does the correct thing: Copy your pointers. But that is not what you want; instead, your copy constructor should allocate new memory and copy the contents of the arrays.

In other words: With your current implementation, you easily leak memory and do double-deletes.

Choices:

  • Read on the The Rule of Three
  • Use standard containers ( std::vector ), which have well defined copy semantics and which manage their memory themselves. When all you have is standard containers, you do not even need a destructor and copy constructor and copy assignment at all (iff you do not delete your matrix class polymorphically)

Also, an advice of style: Don't use empty like this. All standard containers have an empty() method which does something completely different from yours.

Your empty() method is going through rows and rows instead of rows and cols. This is corrupting memory, which is caught when you delete the entries.

You may also be corrupting memory when you are assigning the elements, since it appears your indices are transposed in your example:

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

Don't you mean:

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

This may not be the cause but there is no copy constructor or assignment operator defined for the class MatrixMxN : either define them or make the object non-copyable by declaring them private .

While not the problem in this example, delete[] will be invoked on an uninitialized pointers in the destructor if rows > 0 but cols <= 0 . In the constructor, entry is only initalized if rows > 0 && cols > 0 . If rows > 0 but cols <= 0 the following for loop in the destructor still invokes delete[] entry[i]; :

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

followed by:

delete[] entry; // entry unitialized

EDIT:

This assert in operator() is incorrect:

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

it should be using && :

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM