1

github repo with code Trying to code Matrix class with overloading of some operations.
When I trying to compile with this stroke everything is going wrong

result = (l_mtx + r_mtx);

I get error from g++:
g++ -g3 -std=c++11 -Wall -o matrix matrix_class.h matrix.cpp

matrix.cpp: In function ‘int main()’:
matrix.cpp:36:12: error: no matching function for call to ‘Matrix::Matrix(Matrix)’

result = (l_mtx + r_mtx);   

and then goes several candidates for this function, which I don't really understand.
There are I think copy constructor and several constructors, but this is not operator= which I think supposed to cal in that stroke.

matrix_class.h:73:5: note: Matrix::Matrix(Matrix&) [with type = double]
(no known conversion for argument 1 from ‘Matrix’ to ‘Matrix&’ )

matrix_class.h:46:5: note: Matrix::Matrix(int, int) [with type = double]
(candidate expects 2 arguments, 1 provided)

matrix_class.h:39:5: note: Matrix::Matrix() [with type = double]
(candidate expects 0 arguments, 1 provided)

and then the error:
matrix_class.h:96:18: error: initializing argument 1 of ‘Matrix Matrix::operator=(Matrix) [with type = double]’

I think I'm not correctly code assign operator or copy constructor, but I can't find where the error is. Sorry for dumb question. Thanks for paying attention.

//copy constructor
    Matrix(const Matrix<type> &org)
    {
        cout << "Making a copy of " << this << endl;
        row = org.getRow();
        column = org.getColumn();

        //allocate additional space for a copy
        data = new type* [row];
        for (int i = 0; i < row; ++i)
        {
            data[i] = new type [column];
        }

        for (int i = 0; i < row; ++i)
        {
            for (int j = 0; j < column; ++j)
            {
                data[i][j] = org.data[i][j];
            }
        }
    }

and operator=

//assign constructor
Matrix<type> operator = (Matrix<type> r_mtx)
{
    if (row == r_mtx.getRow())
    {
        if (column == r_mtx.getColumn())
        {
            //TODO: удалить прежний объект?
            Matrix<type> temp(row, column);
            for (int i = 0; i < row; ++i)
            {
                for (int j = 0; j < column; ++j)
                {
                    temp.data[i][j] = r_mtx[i][j];
                }
            }
            return temp;
        }
        else
        {
            cout << "Assign error: matrix column are not equal!" << endl;
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        cout << "Assign error: matrix rows are not equal!" << endl;
        exit(EXIT_FAILURE);
    }
}
Alexander
  • 105
  • 1
  • 2
  • 16
  • 1
    Your copy constructor should probably take `const Matrix&`. – Brian Bi Mar 06 '15 at 21:05
  • You should copy the relevant parts of your code into your question, not link to an external website. – Christian Hackl Mar 06 '15 at 21:07
  • @Brian then I will not allowed to change it fields – Alexander Mar 06 '15 at 21:15
  • @Alexander Exactly. It's a *copy*. It shouldn't modify the original at all. – aruisdante Mar 06 '15 at 21:18
  • If you have fields that need to be modified on copy, maybe you should declare them `mutable`? – Brian Bi Mar 06 '15 at 21:18
  • Also, in general I'm not sure what the advantage is to having size checks on an assignment in a matrix class that doesn't have fixed-allocation of size (I.E. isn't defined as `Matrix` so that allocation happens at compile time). If I can't overwrite an arbitrary matrix without having to have already declared a valid matrix with the correct sizes, I might as well just use the copy constructor. Otherwise I waste an array allocation for no reason. Have a look at the [canonical implementations](http://en.cppreference.com/w/cpp/language/operators) for `operator=`. – aruisdante Mar 06 '15 at 21:29
  • @aruisdante thanks, I will take it into account, thanks you all, I will refactor my code. – Alexander Mar 06 '15 at 21:42

2 Answers2

1

Declare the copy assignment operator like

Matrix<type> & operator = ( const Matrix<type> &r_mtx )

The problem is that temporary objects may not be bound to a non-const reference.

Take into account that assignment operators should return reference to the left hand object.

Your assignment operator is in essence invalid. Instead of assigning the left hand object it creates a temporary object. So there is no any assigning.

It could be defined something like this

Matrix<type> & operator = ( const Matrix<type> &r_mtx )
{
    if (row == r_mtx.getRow())
    {
        if (column == r_mtx.getColumn())
        {
            for (int i = 0; i < row; ++i)
            {
                for (int j = 0; j < column; ++j)
                {
                    data[i][j] = r_mtx[i][j];
                }
            }
            return *this;
        }
        else
        {
            cout << "Assign error: matrix column are not equal!" << endl;
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        cout << "Assign error: matrix rows are not equal!" << endl;
        exit(EXIT_FAILURE);
    }
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • I get an error if I try to change fields of this In instantiation of ‘Matrix& Matrix::operator=(const Matrix&) [with type = double]’: matrix.cpp:30:11: required from here matrix_class.h:98:17: error: passing ‘const Matrix’ as ‘this’ argument of ‘int Matrix::getRow() [with type = double]’ discards qualifiers [-fpermissive] if (row == r_mtx.getRow()) – Alexander Mar 06 '15 at 21:32
  • @Alexander Member functions getRow() and getColumn() shall be defined with qualifier const For example int getRow() const; – Vlad from Moscow Mar 06 '15 at 21:35
  • @Alexander and in the general sense, any method that does not mutate the state of the object should always be `const`. Here is a [good tutorial](http://duramecho.com/ComputerInformation/WhyHowCppConst.html) on `const`, when to use it, and why. – aruisdante Mar 06 '15 at 21:52
0

Here is a simpler suggestion using a variation on the copy and swap idiom:

Matrix<type> & operator = ( Matrix<type> r_mtx )  //  pass by value
{
    if ( getRow() != r_mtx.getRow() || getColumn() != r_mtx.getColumn() )
        throw std::runtime_error("Wrong dimension in matrix assigment");

    std::swap(data, r_mtx.data);
    return *this;
}

If you want to allow assigning even if the target matrix is not the right size already, then you can take out the dimension check, and copy or swap row and column over (and any other member variables).

Using throw is preferable to exit because it gives the user of your code more options. If they don't catch then it is equivalent to exit anyway.

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365