简体   繁体   中英

Copy constructor and operator= for a dynamic array inside a class

I need some help to implement a copy constructor and a operator= for my dynamic array inside my class. Im not allowed to use a vector at this point

Here is mye code: Class:

    class Matrix{
    private:
        int rows;
        int columns;
        double* matrix;
    public:
        Matrix();
        explicit Matrix(int N);
        Matrix(int M, int N);
        void setValue(int M, int N, double value);
        double getValue(int M, int N);
        bool isValid() const;
        int getRows();
        int getColumns();
        ~Matrix();
        friend ostream& operator<<(ostream &out, Matrix&matrix1);       
};

And my code:

Matrix::Matrix(){
    matrix = NULL;
}

Matrix::Matrix(int N){
    matrix = new double[N * N];
    rows = N;
    columns = N;

    for(int i = 0; i < N; i++){
        for(int j = 0; j < N; j++){
            if(i==j)
                matrix[i * N + j] = 1;
            else
                matrix[i * N + j] = 0;
        }
    }
}

Matrix::Matrix(int M, int N){
    matrix = new double[M * N];
    rows = M;
    columns = N;

    for(int i = 0; i < M; i++){
        for(int j = 0; j < N; j++)
            matrix[i * N + j] =  0;
    }
}

Matrix::~Matrix(){
    delete [] matrix;
}

void Matrix::setValue(int M, int N, double value){
    matrix[M * columns + N] = value;
}

double Matrix::getValue(int M, int N){
    return matrix[M * columns + N];
}

bool Matrix::isValid() const{
    if(matrix==NULL)
        return false;
    else
        return true;
}

int Matrix::getRows(){
    return rows;
}

int Matrix::getColumns(){
    return columns;
}

ostream& operator<<(ostream &out, Matrix&matrix1){
    if(matrix1.isValid())
        for(int i = 0; i < matrix1.getRows(); i++){
            for(int j = 0; j < matrix1.getColumns(); j++)
                out << matrix1.getValue(i,j) << "\t";
            out << endl;
        }
    else
        out << "Matrisen er ikke gyldig."; //the matrix is not valid
    return out;
}

Would something like this work?

Matrix &operator=(const Matrix &m) {*(this->matrix) = *(m.matrix);}
Matrix(const Matrix &rhs) : matrix(0) {
        this->matrix = new double();
        *(this->matrix) = *(rhs.matrix);
    }

Im also going to overload the operator += and +. I've tried to implement this as:

const Matrix operator+=(Matrix matrix1, Matrix matrix2){
        if(!matrix1.isValid() || !matrix2.isValid()){
            cout << "En av matrisene er ugyldig"; //one of the matrices are invalid
            return Matrix::Matrix(); //returning a NULL matrix
        }
        else{
            if(matrix1.getColumns()==matrix2.getColumns() && matrix1.getRows()==matrix2.getRows()){
                Matrix temp(matrix1.getRows(), matrix1.getColumns());
                for(int i = 0; i < matrix1.getRows(); i++){
                    for(int j = 0; j < matrix1.getColumns(); j++)
                        temp.setValue(i,j,(matrix1.getValue(i,j) + matrix2.getValue(i,j)));
                }
                return temp;
            }
            else{
                cout << "Matrisene har ikke samme dimensjon"; //the matrices does not have the same dimensions
                return Matrix::Matrix();
            }
        }
    }
    const Matrix operator+(Matrix matrix1, Matrix matrix2){
        return matrix1 += matrix2;
    }

Would something like this work? Is it better to overload the operators as a part of the class, a friend of the class or just outside the class?

Any help is appriciated.

Why did you delete the other question? I hope it was just an error: (see the EDIT at end)

Yes, you have many issues in your code, and even in your design.

Just to give you an idea:

Your Matrix have no copy constructor (or move) and not “ = ” too. They are:

Matrix(const Matrix &m);

And (move constructor):

Matrix(Matrix &&m);

And

Matrix& operator=( const Matrix &m);
Matrix& operator=( Matrix &&m);

If you don't define these special functions, the compiler will define it for you. But they will only apparently work. The program compile but work wrong ( shallow vs. deep copy problem , and pass by value or by reference ). I gees you use new in the constructor to build the matrix private array. And in the destructor you delete[]matrix . Each time you pass a Matrix by value it get copy-ed using the complier generated copy constructor, with just copy the value of the members of Matrix , thus copying the value of the pointer matrix but not the array. At the end of the call this local copy will be destructed, and your original matrix get deleted!! This is just one of the many problems. Sufficient for you to sit, read a litter more and try again latter. A "simple" fix maybe to replace

 double *matrix;

by

std::vector<double> matrix;

Now the compiler generated functions will work a lot better.

And yes, if you want to use [] with Matrix you need to define it. And += is a binary operator, that take one parameter (the left is always this , a pointer to the object with call it). Here you want just a free +() with 2 arguments or a member +() with one. Hope this help you. Ask again.

EDIT: Does this work as an operator= ?

Matrix &operator=(const Matrix &m) {*matrix = *(m.matrix);}

No, this will copy only the first double. You will need a loop over the entery array and copy each element. And first you need to be sure that the size of the matrixes are compatible. (If you use the vector matrix=m.matrix will work.). A fix for your copy constructor could be:

Matrix::Matrix(const Matrix &m):   rows    (m.rows), 
                                   columns (m.columns), 
                                   matrix  (new double[rows* columns]) 
{
    for(int i = 0; i < rows; i++)
        for(int j = 0; j < columns; j++)
            matrix[i * columns + j] =  m.matrix[i * columns + j];

} 

And to move:

Matrix::Matrix(     Matrix &&m):   rows    (m.rows), 
                                   columns (m.columns), 
                                   matrix  (m.matrix) 
{
     m.matrix=nullptr;
     m.rows= m.columns=0;
} 

This move can dramatically improve the efficiency of coping Matrixes when you don't care about the original value, with is for example the case with temporal objects. In this case, you don't need to iterate copying each array element: you simple steal the full array. The good thing about it is that in most situations the compiler will pick “automatically” the correct variant (copy or move) for you.

Matrix &operator=(const Matrix &m) {*(this->matrix) = *(m.matrix);}

This will only assign the first element of lhs' matrix to be the same as the first element of the rhs' matrix. On top of that, this would require that both matrices have been initialized with the same number of rows and columns. You can use memcpy or a loop to assign all elements.

Matrix(const Matrix &rhs) : matrix(0) {
    this->matrix = new double();
    *(this->matrix) = *(rhs.matrix);
}

This will fail because you are not allocating enough memory for the matrix member of the newly constructed instance (unless the other matrix is a 1x1 matrix). Assuming the matrices are stored in row-major order, it should look like this:

Matrix(const Matrix &rhs) : matrix(0), rows(rhs.rows), columns(rhs.columns) {
    this->matrix = new double[rows * columns];
    for (size_t r = 0; r < rows; r++) {
       for (size_t c = 0; c < columsn; c++) {
          this->matrix[r * columns + c] = rhs.matrix[r * columns + c];
       }
    }
}

EDIT: Just to make sure, here's how I would do the assignment operator:

Matrix &operator=(const Matrix &m) {
    if (rows * columns != m.rows * m.columns) {
        delete [] this->matrix;
        this->matrix = new double[m.rows * m.columns];
    }
    rows = m.rows;
    columns = m.columns;
    for (size_t r = 0; r < rows; r++) {
       for (size_t c = 0; c < columsn; c++) {
          this->matrix[r * columns + c] = m.matrix[r * columns + c];
       }
    }
    return *this;
}

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