Destruktor po wywołaniu funkcji.

0

Witam,
Piszę sobie mały program operujący na macierzach... i zasadniczo mam problem tego typu że jak przeciążam operator "+" to program uruchamia destruktor kilka razy i to jakiś losowych obiektów, gdyż je numerowałem i sprawdzałem co jest nie tak.

Mam klasę zdefiniowaną w pliku nagłówkowym następująco.

class Matrix 
{
    private:

        double** elements;
        int rows;
        int cols;
        double** Resize(double ** elements, int new_rows, int new_cols);

    public:
        Matrix(int rows, int cols);  // Konstruktor
        ~Matrix();                   // Dekonstruktor

        void EnterData();
        void ShowData();
        int LU(Matrix* L, Matrix* U, int mode=0);  // not all matrix

        Matrix operator+ (Matrix B);

        double Determinant();
        double Rank();
        Matrix* Transpose();
        void    Transpose(bool);
        Matrix* Inversion();

    protected:
        int z;
}; 

Funkcje

Matrix::Matrix(int rows, int cols)
{
            this->rows = rows;
            this->cols = cols;
            elements = new double* [rows];
            for(int i=0;i<rows;i++)
            {
                elements[i]=new double[cols];
                for(int j=0;j<cols;j++)
                    elements[i][j]=0;
            }
}

Matrix::~Matrix()
{
            if(elements==NULL) return;

            for(int i=0;i<rows;i++)
            {
                for(int j=0;j<cols;j++)
                    elements[i][j]=NULL;
                delete[] elements[i];
            }
            delete[] elements;
            elements = NULL;
            rows=0;
            cols=0;
}

Matrix Matrix::operator + (Matrix B)
{
    Matrix Wynik_dodawania(this->rows,this->cols);

    for( int i=0; i<this->rows; i++ ) 
    {
        for( int j=0; j<this->cols; j++ ) 
        {
            Wynik_dodawania.elements[i][j] = this->elements[i][j] + B.elements[i][j];
        }
    }
    return Wynik_dodawania;
} 
void Matrix::EnterData()  // dodac walidacje danych wprowadzanych
{
    for(int i=0;i<rows;i++)
        for(int j=0;j<cols;j++)
        {
            std::cout<<"Podaj wartosc w wierszu "<<i<<" kolumnie "<<j<<" "; 
            std::cin>>elements[i][j];
        }

    system("cls");

}

void Matrix::ShowData()  // dodac walidacje danych wprowadzanych
{

    for(int i=0;i<rows;i++)
    {
        for(int j=0;j<cols;j++)
        {
            std::cout<<elements[i][j]<<" ";
        }
        std::cout<<std::endl;
    }

}

I w samej funkcji main mam coś takiego

int main()
{
    Matrix A(2,2);
    A.EnterData();
    A.ShowData();
    Matrix B(2,2);
    B= A+A;
    B.ShowData();
    return 0;
} 

tak jak wspomniałem program wykrzacza się po wykonaniu dodawania na destruktorze który wywołuje się trzy razy, jakaś porada dla mnie?

1

Masz przekazywanie przez wartość:
Matrix operator + (Matrix B)
zaś brak konstruktora kopiującego.

Masz użyte przepisanie:
B= A+A;
zaś brak przeciążenia operator=

1

A gdzie masz konstruktor kopiujący i operator przypisania? Teraz usuwasz sobie cały czas dane z macierzy, bo wskaźnik jest po prostu przepisywany (a to nie wskaźnik powinien być kopiowany, tylko dane, można też wykorzystać COW albo inne bajery). Poza tym operator + powinien i tak przyjmować stałą referencję.

Edit: ojej, spóźniłem się nieco.

0

Dzięki panowie za szybką odpowiedź :)

Teraz działa i zmiany wyglądają tak:


Matrix::Matrix(const Matrix &Copy) //Kopiujący
{
    rows = Copy.rows;
    cols = Copy.cols;
    elements = new double* [rows];
    for(int i=0;i<rows;i++)
    {
        elements[i]=new double[cols];
        for(int j=0;j<cols;j++)
            elements[i][j]=Copy.elements[i][j];
    }

}

Matrix Matrix::operator + (const Matrix &B)
{
    Matrix Wynik_dodawania(this->rows,this->cols);
    for( int i=0; i<this->rows; i++ ) 
    {
        for( int j=0; j<this->cols; j++ ) 
        {
            Wynik_dodawania.elements[i][j] = this->elements[i][j] + B.elements[i][j];
        }
    }
    return Wynik_dodawania;
}

Matrix& Matrix::operator= (const Matrix &A)
{
    for( int i=0; i<A.rows; i++ ) 
    {
        for( int j=0; j<A.cols; j++ ) 
        {
            this->elements[i][j] = A.elements[i][j];
        }
    }
    return  *this;
}

I czy wszytko jest tak jak powinno czy jeszcze inaczej powinno się pisać?

0

Ja bym dodał jeszcze move constructor.

0

Matrix Matrix::operator + (const Matrix &B)const ...

W Matrix& Matrix::operator= (const Matrix &A) - skąd założenie że A ma taki sam wymiar co this ? Brakuje resize

0

To const powinno być czy nie?

Resize jest, trochę naokoło zrobiony, ale jest.

Edit: Tylko że nie wkleiłem -.-

Matrix& Matrix::operator= (const Matrix &A)
{
    if(this->rows != A.rows || this->cols != A.cols)
    {
        elements = this->Resize(elements, A.rows , A.cols);
    }
    for( int i=0; i<A.rows; i++ ) 
    {
        for( int j=0; j<A.cols; j++ ) 
        {
            this->elements[i][j] = A.elements[i][j];
        }
    }
    return  *this;
} 
double** Matrix::Resize(double ** elements, int new_rows, int new_cols)
{
            for(int i=0;i<rows;i++)
            {
                for(int j=0;j<cols;j++)
                    elements[i][j]=NULL;
                delete[] elements[i];
            }
            delete[] elements;
            double ** elements2;
            this->rows = new_rows;
            this->cols = new_cols;
            elements2 = new double* [rows];
            for(int i=0;i<rows;i++)
            {
                elements2[i]=new double[cols];
                for(int j=0;j<cols;j++)
                    elements2[i][j]=0;
            }
            return elements2;
} 
0
Matrix& Matrix::operator= (const Matrix &A)

po pierwsze, trzeba na początku sprawdzić czy &A==this, jeżeli tak to od razu wyjść:

if (this==&A) return *this;

po drugie, jak już kol. _13th_Dragon wspomniał, trzeba zaalokować nową pamięć, jeśli rozmiar miałby się zmienić, albo this->elements jest NULL.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0