Search code examples
c++matrixdelete-operator

delete[] triggers breakpoint on return from function


I wrote a matrix class that can do certain matrix operations, but my newest function, transpose(), triggers a breakpoint on delete[]. Here are the relevant parts:

class Matrix {
    float* M;
    int n, k;
    void allocM(int _n, int _k) {
        n = _n;
        k = _k;
        M = new float[n * k];
    }
    void delM() {
        delete[] M;
    }
    public:
    inline float operator()(int i, int j) const { return M[i * k + j]; }
    inline float& operator()(int i, int j) { return M[i * k + j]; }
    Matrix(int _n, int _k) {
        allocM(_n, _k);
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < k; ++j) {
                operator()(i, j) = 0;
            }
        }
    }
    Matrix(const Matrix& source) {
        allocM(source.n, source.k);
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < k; ++j) {
                operator()(i, j) = source(i, j);
            }
        }
    }
    ~Matrix() {
        delM();
    }
    Matrix& operator=(const Matrix& source) {
        delM();
        allocM(source.n, source.k);
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < k; ++j) {
                operator()(i, j) = source(i, j);
            }
        }
        return *this;
    }
    Matrix operator*(const Matrix& other) const {
        Matrix matrix = Matrix(n, other.k);
        for (int i = 0; i < matrix.n; ++i) {
            for (int j = 0; j < matrix.k; ++j) {
                for (int l = 0; l < k; ++l) {
                    matrix(i, j) += operator()(i, l) * other(l, j);
                }
            }
        }
        return matrix;
    }
    Matrix transpose() const {
        Matrix matrix = Matrix(k, n);
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < k; ++j) {
                matrix(k, n) = operator()(n, k);
            }
        }
        return matrix;
    }
};

I then multiply two matrices, basically. Something like:

matrix0 = matrix1 * matrix2.transpose();

Result: a breakpoint is triggered in delM() { delete[] M; }

I added a breakpoint to the matrix multiplication. This is what happens:

Program enters transpose() function, then Matrix(int, int) constructor runs. Then the nested loops run in transpose(), followed by return matrix;, where it runs Matrix(const Matrix& source), then back to return matrix;, then delM() and then it breaks on the line delete[] M;

I have only included the assignment operator function to show why I have a delM() function. I have tried zeroing *M out after declaration and in delM() after delete, but it didn't help.

What am I doing wrong?


Solution

  • In transpose, you should change:

    matrix(k, n) = operator()(n, k);
    

    To:

    matrix(j, i) = operator()(i, j);
    

    You're accessing data off the end of the array M, causing heap corruption. It may be a good idea to do a bounds check in operator(), just to catch these kinds of things in the future.

    And, as I mentioned in a comment, in operator=, add:

    if (this == &source) return;
    

    Or preferably (as Puppy points out), design it such that self-assignment is safe. Crude example:

        float *temp = M;
        allocM(source.n, source.k);
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < k; ++j) {
                operator()(i, j) = source(i, j);
            }
        }
        delete []temp;
        return *this;