-1

I've been making a Matrix class over the course of the week and have run into a problem that has left me stumped: the return statement of one of my functions is throwing a bad_array_new_length exception!

Here's example code that I used to find this out:

Matrix Matrix::operator*(Matrix& mat)
{
    if (this->columns != mat.rows)
    {
        //Do code if Matrix can't be multiplied.
    }
    else
    {
        Matrix result(this->rows, mat.columns);

        //Multiply Matrices together.

        //Print out result to prove the local Matrix works fine.
        //It does.

        try
        {
            return result;
        }
        catch (const exception& e)
        {
            cout << "return exception: " << e.what() << endl;
            return result;  //To be caught again in the test.
        }
    }
}

Low and behold, when I run the function it prints out "return exception: bad_array_new_length" onto the console.

The function was tested like so:

try
{
    answer = A1 * B1;   //A1 and B1 are able to be multiplied.
}
catch (const exception& e)
{
    cout << e.what() << endl;
}

The test also catches the exception and prints it out as well.

After doing a little research, the bad_array_new_length exception is only thrown when an array is given an invalid length. The Matrix class does use a multidimensional array to store its doubles, but I would think that this isn't the root of the problem because the local Matrix works perfectly as intended.

Here is how the multidimensional array is declared and initialized in the constructor, just in case:

//Matrix.h

unsigned int rows;
unsigned int columns;

double ** storage = new double*[rows];  //Multidimensional array isn't completely formed, see the constructor.

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

//Matrix.cpp

Matrix::Matrix(unsigned int x, unsigned int y)
:
    rows(x),
    columns(y)
{
    for (unsigned int i = 0; i < rows; ++i) //Completes the formation of the multidimensional array.
        storage[i] = new double[columns];

    for (unsigned int i = 0; i < rows; ++i)
    {
        for (unsigned int q = 0; q < columns; ++q)
        {
            storage[i][q] = 0;  //Initializes each value in the array as 0.
        }
    }
}

/////////////////////////////////////////////////////////////////////////////////////////////////////

EDIT:

Here is the defined copy constructor and assignment operator:

Matrix::Matrix(const Matrix& obj)
{
    rows = obj.rows;
    columns = obj.columns;

    for (unsigned int i = 0; i < rows; ++i)
    {
        for (unsigned int q = 0; q < columns; ++q)
        {
            storage[i][q] = obj.storage[i][q];
        }
    }
}

////////////////////////////////////////////////////////////////////////////////

bool Matrix::operator=(Matrix mat)
{
    rows = mat.rows;
    columns = mat.columns;

    for (unsigned int i = 0; i < rows; ++i)
    {
        for (unsigned int q = 0; q < columns; ++q)
        {
            storage[i][q] = mat.storage[i][q];
        }
    }

    return true;
}

Out of curiosity, I changed the code in the test to only be:

try
{
    A1 * B1;    //Removed assignment to answer Matrix.
}
catch (const exception& e)
{
    cout << e.what() << endl;
}

..and the exception still threw as normal.

  • Not all the paths of `Matrix Matrix::operator*(Matrix& mat)` return a value. – user0042 Oct 04 '17 at 02:45
  • Your `Matrix` class lacks a user-defined copy constructor and assignment operator. Thus returning `Matrix` is undefined behavior due to probable memory corruption. Also, you don't or you didn't show returning a value in one or more code paths of your `operator *` -- again, undefined behavior. Oh, and if you really did write a copy constructor and assignment operator, wouldn't you think piece of information is the most important thing you left out of your post. since everything hinges on those functions to be written correctly? – PaulMcKenzie Oct 04 '17 at 04:17
  • [What is the rule of 3?](https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three) – PaulMcKenzie Oct 04 '17 at 04:22
  • Today it's the rule of 3 or 5. (either both or neither of move constructor& move assignment). But preferably the rule of zero (use in-built RAII to avoid writing any of these - where possible). – Persixty Oct 04 '17 at 14:20

1 Answers1

-1

Fixed the issue, all I had to do was changed how memory was allocated in the class declaration and in the constructor.