1

I am quite new to C++. My problem is to write an OOP C++ program about matrix (create a matrix class and add some methods to this class) Here is my code:

#include <iostream>
#include <iomanip>

using namespace std;

class Matrix 
{
    private:
        int col, row;
        double *a;
    public:
        Matrix(int col = 1, int row = 1) {
            this->col = col; this->row = row;
        }
        ~Matrix() {
            delete a;
            col = row = 0;
        }
        void insertMatrix() {
            a = new double[this->col * this->row];
            for (int i = 0; i < this->row; i++)
                for (int j = 0; j < this->col; j++) {
                    cout << endl << "a[" << i + 1 << "][" << j + 1 << "] = ";
                    cin >> this->a[i * this->col + j];
                }
        }
        void printMatrix() {
            for (int i = 0; i < this->row; i++) {
                for (int j = 0; j < this->col; j++)
                    cout << setw(9) << this->a[i * this->col + j];
                cout << endl;
            }
            cout << endl;
        }
        int getCol() {
            return col;
        }
        int getRow() {
            return row;
        }
        Matrix operator+(Matrix);
        Matrix operator-(Matrix);
};

Matrix Matrix::operator+(Matrix x) {
    if (x.col != col || x.row != row) {
        cout << endl << "Can't add these two matrices";
        exit(0);
    }
    Matrix sum(x.col, x.row);
    sum.a = new double(sum.col * sum.row);
    for (int i = 0; i < this->col * this->row; i++)
        sum.a[i] = a[i] + x.a[i];
    return sum;
}

Matrix Matrix::operator-(Matrix x) {
    if (x.col != this->col || x.row != this->row) {
        cout << endl << "Can't subtract these two matrices";
        exit(0);
    }
    Matrix dif(this->col, this->row);
    dif.a = new double(dif.col * dif.row);
    for (int i = 0; i < this->col * this->row; i++)
        dif.a[i] = this->a[i] - x.a[i];
    return dif;
}

int main()
{
    int row, col;
    cout << endl << "Column = "; cin >> col; cout << endl << "Row = "; cin >> row;
    Matrix A(col, row), B(col, row);
    A.insertMatrix(); B.insertMatrix();
    cout << "Matrix A: " << endl; A.printMatrix(); 
    cout << "Matrix B: " << endl; B.printMatrix();
    cout << "Matrix (A + B)" << endl; (A + B).printMatrix();
    cout << "Matrix (A - B)" << endl; (A - B).printMatrix();
}

I don't see any mistake at all. I can compile the program. But every time I try to input some numbers, the program keeps freezing with the message "stop working" and gets the wrong answer. I use Orwell Dev C++ in Windows 8. Can anyone explain why?

pexea12
  • 1,069
  • 2
  • 18
  • 36
  • 2
    This is a bit difficult to tell; can you use a debugger or provide a smaller portion of the program which exhibits the same behaviour? – Codor Jan 04 '15 at 19:47
  • Well, actually I try to debug but I can't find the mistake. The method printMatrix() works out well, I believe. However, I think the problem is about 2 method operator+ and operator- I think there are some problems with (A + B).printMatrix() and (A - B).printMatrix() but I can't figure out. Whenever I delete these two lines, the program is fine. – pexea12 Jan 04 '15 at 19:51
  • If you comment them out does the problem disappear? – lared Jan 04 '15 at 19:52
  • Go to your debug -> exceptions -> win32 exceptions and click the check box next to Access Violation. That will get the debugger to stop on the access violation. When it stops go up the callstack to the line of code in your program. – drescherjm Jan 04 '15 at 19:54
  • Yes, the problem disappers when I delete two lines of (A + B).printMatrix() and (A - B).printMatrix(). Maybe you can try to run this code by yourself and see the problem. Thank you so much! – pexea12 Jan 04 '15 at 19:54
  • @drescherjm Thanks, let me try if it could help. – pexea12 Jan 04 '15 at 19:55
  • Just by inspecting the code I can't find a bug, but I find it counter-intuitive that the member `a` which stores the actual data is not allocated in the constructor of `Matrix`, but in the operators. – Codor Jan 04 '15 at 19:55
  • You are returning a local Matrix (sum and diff) that will go out of scope and you are not following the rule of 3. – drescherjm Jan 04 '15 at 19:56
  • @drescherjm I am sorry but I can't find the debug options. I can't find it in Orwell Dev C++. I am quite new to C++. Can you tell a little bit more? – pexea12 Jan 04 '15 at 19:57
  • Is this Visual Studio? – drescherjm Jan 04 '15 at 19:58
  • No, it is Orwell Dev C++ – pexea12 Jan 04 '15 at 19:59
  • 1
    @drescherjm You are right, but this would not be a problem if the rule of three had been applied; the local result would be copied. – Codor Jan 04 '15 at 19:59
  • The rule of zero is better. – Lightness Races in Orbit Jan 04 '15 at 20:01
  • @PeaNguyen - The high-level problem is that you're looking at code and you say you see no mistakes. Of course you won't see any mistakes, since you are not experienced enough to spot them. For example, how would you know about applying the "rule of 3" to your Matrix class, unless someone told you about it? – PaulMcKenzie Jan 04 '15 at 20:03
  • Yes, I haven't read about this rule. Thank you! – pexea12 Jan 04 '15 at 20:05

3 Answers3

5

One mistake is that you're using new incorrectly.

 sum.a = new double(sum.col * sum.row);

The above creates a single double dynamically, and initializes the value to sum.col * sum.row.

You should be using new[]:

 sum.a = new double[sum.col * sum.row];

Then you must use delete[], not delete when using new[].

Another error is that you did not initialize the a pointer in your constructor. When the Matrix is destroyed, the destructor will issue a delete on a pointer that is pointing to who-knows-where.

Thus, this simple one line program has problems:

int main() {
   Matrix m;
}  // < -- problems here 

The fix is to make sure your pointers are initialized:

Matrix(int mcol = 1, int mrow = 1) : a(0), col(mcol), row(mrow) {}

Note that a is now initialized to 0. Also note the usage of the member initialization list.

However, another mistake is that your Matrix class lacks a user defined copy constructor and assignment operator. When you return or pass a Matrix by value as you're doing here:

Matrix Matrix::operator+(Matrix x)

The copy will only do a shallow copy on the pointers, and your program thus will have memory leaks, double deallocation errors, etc. Please read up on the "rule of 3":

What is The Rule of Three?

Other issues:

Do not call exit(0) within class code. If I wanted to use your Matrix class, and I give operator + a Matrix that isn't the correct size, please don't close the application down on me! Instead, throw an exception, or issue an assert().

See here: exit() call inside a function which should return a reference

Community
  • 1
  • 1
PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
  • Just for clarification - `new double(sum.col * sum.row)` returns a pointer to a newly allocated double and initializes the memory with the value `sum.col * sum.row`? – Codor Jan 04 '15 at 19:56
  • Yes, that's right. Let me see it again. Thank you so much! – pexea12 Jan 04 '15 at 19:59
  • Yes, this is quite tricky for me. It took me about 3 hour and I couldn't find the mistake. Feel relieved now! – pexea12 Jan 04 '15 at 20:05
  • @PeaNguyen - I updated my post. You have other issues that can be seen with a simple one line program. – PaulMcKenzie Jan 04 '15 at 20:21
4

The main problem in your program is that in the operators you overload, you return a stack allocated Matrix object which will call the copy constructor.

But since you don't define one, the compiler will generate it for you, doing a bit-wise copy, which means that the d pointer in the copied object will point to the same location as in the object from stack.

Therefore, the destructor is called two times

  • when leaving the function overloads;
  • when destroying the copied object, which happens immediately after this line:

(A + B).printMatrix();

That is why your program will terminate abnormally with an error similar to this:

Error in `./rez': free(): invalid next size (fast): 0x00000000020390c0

As others suggest, you wouldn't have encountered this problem if you had respected The rule of 3 (or 5 in C++11/14).

Călin
  • 347
  • 2
  • 13
2

Another mistake is a blatant violation of the Rule Of Three; copying your Matrix ruins its ownership semantics.

Why don't you use a std::vector<double> instead.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • Absolutely - returning the locally defined result as in the operators requires a custom copy constructor. – Codor Jan 04 '15 at 20:02