locales Objekt zerstören

BLR

Erfahrenes Mitglied
Hallo zusammen,

ich versuche gerade zwei gleiche Objekte durch die Überladung von dem Plus-Operator miteinander zu addieren.
Dabei erzeuge ich innerhalb der Überladung ein locales Objekt, welches dann die addierten Wert in sich speichert und dann gebe ich dieses locale Objekt zurück.
Das funktioniert soweit, allerdings springt das Programm nach der Rückgabe in den Destructor und will dieses locale Objekt wieder zerstören...,

Überladung:

C++:
Obj Obj::operator +(const Obj& m) const{

    Obj mTmp(m.columnCount,m.rowCount);
    for (int i = 0; i < this->rowCount; i++) {
    
        for (int y = 0; y < this->columnCount; y++) {
        
            std::cout << this->daten[i][y] << "\n";
            mTmp.daten[i][y] = this->daten[i][y] + m.daten[i][y];
        
        }
    }


    return mTmp;
}

der Konstruktor (dynamisches Erzeugen von zweidimensionalen Array):

C++:
Obj::Obj(int reihen, int spalten) {
    rowCount = reihen;
    columnCount = spalten;
    daten = new double*[reihen];
    for (int i = 0; i < reihen; i++) {
        daten[i] = new double[spalten];
    }
}

Nach der Rückgabe springt er in den Destructor und will den mTmp zerstören:

C++:
Obj::~Obj() {


    for (int i = 0; i < this->rowCount; i++) {
        delete[] this->daten[i];
    }
    delete[] daten;
}

Wie kann ich das Problem lösen`?
Vielleicht liegt das Problem am Destructor, da das zerstören von globalen Objekten keine Fehler verursacht

Nachtrag:
Ich habe schon an mehreren Stellen gesehen, dass dieser Destructor korrekt ist.
mit der Zeile:

std::cout << *(daten);
kriege ich auch den tatsächlichen Wert, nur das wieder Freigeben funktioniert nicht, wenn es sich um dieses local-angelegtes Objekt handelt, aber bei globalen funktioniert das.


Die Fehlermeldung beim debuggen ist ein SIGABRT Signal.
Hat wohl was mit dem Speicherzugriff zutun, aber ich verstehe nicht, warum ich nicht den Speicher freigeben kann, wenn ich den Wert davon auslesen kann....

Danke
 
Zuletzt bearbeitet:
Hallo,

wie du ja schon festgestellt hast wurde das Objekt innerhalb der Funktion lokal erzeugt und wird natürlich auch nach Ende der Funktion gelöscht.

Ein Variante das Objekt in der Funktion zu erzeugen und nach außen zu übergeben wäre einen Zeiger auf das Objekt zu erstellen und dann ein Objekt mittels "new" zu erstellen und dann diesen Zeiger zurückzugeben.
Das ist allerdings etwas riskant, weil man außerhalb der Funktion auch das löschen des Objekts bedenken muss, daher etwas unschön (mit shared pointern, kann das allerdings auch besser gemacht werden).
 
Ausserhalb der Funktion? Wäre am Ende der Main kein guter Ort dafür?

also hab ich dann folgendes gemacht:
In der Main:
C++:
Obj* testObj = obj1-obj2;

In der Obj.cpp
C++:
Obj* Obj::operator -(const Obj& m) const {

    Obj*mTmp = new Obj(m.columnCount, m.rowCount);

    mTmp->name = "locales Objekt";
    for (int i = 0; i < this->rowCount; i++) {

        for (int y = 0; y < this->columnCount; y++) {

            mTmp->daten[I][y] = this->at(i, y) - m.at(i, y);
        }
    }
    return mTmp;  //Den Zeiger an den Zeiger in der main übergeben
}

Danach möchte ich den Speicher in der Main freigeben:

C++:
delete testObj;

dann lande ich im Destruktor, wo der selbe Fehler in der Delete-Zeile erneut auftritt

C++:
for (int i = 0; i < this->rowCount; i++) {
            delete[] daten[I];
        }
 
Zuletzt bearbeitet:
Mit außerhalb der Funktion meinte ich, außerhalb des Bereichs der den Speicher zuweist. Das Problem was ich meine ist nämlich, dass du jetzt zwar weißt, dass du den Speicher freigeben musst, jemand anderes der deinen Code evtl. auch nutzt aber unter umständen nicht. Daher ist das im Sinne der Datenkapselung immer besser dafür zu sorgen, dass es automatisch passiert, bzw. das Objekt selbst macht. Aber das ist auch eigentlich ein ganz anderes Thema bzgl. Software-Design. Zumal die Variante die du nutzt ja nicht falsch ist.

Edit:
Den Code den ich vorher geschrieben habe war natürlich Schwachsinn, daher habe ich den wieder entfernt.

Ich habe mir mal selbst ein Minimalbeispiel programmiert, da funktioniert der Code. Da war unteranderem der Fehler das du in der Operatorfunktion wohl Zeilen und Spalten vertauscht hast (bitte einmal bei dir überprüfen). Um dabei sicher zugehen würde ich dich bitten ein Minimalcode von dir zu posten, bei dem der Fehler auftritt, da ich so gerade nur raten kann.
 
Zuletzt bearbeitet:
ich versuche gerade zwei gleiche Objekte durch die Überladung von dem Plus-Operator miteinander zu addieren.
Dabei erzeuge ich innerhalb der Überladung ein locales Objekt, welches dann die addierten Wert in sich speichert und dann gebe ich dieses locale Objekt zurück.
Das funktioniert soweit, allerdings springt das Programm nach der Rückgabe in den Destructor und will dieses locale Objekt wieder zerstören...,

Hallo BLR,

Du solltest deiner Klasse noch einen Copy Constructor spendieren. Der wird aufgerufen, wenn du das lokale Objekt zurückgibst (es wird eine Kopie auf den Stack gelegt) und du verlierst dann nicht deine Daten. Aktuell wird nämlich der Default Copy Constructor verwendet und der kopiert nicht deine Daten.

Irgendwelche Konstrukte mit globalen Objekten kannst du dir sparen.

Gruß
MCoder
 
Vielen Dank :)

ich hab tatsächlich einen Copy-Construktor geschrieben, der an anderen Stellen funktioniert....im Folgenden sieht ihr meine Klasse, wo ich die Variante mit dem Zeiger auf Heap in der Überladung nicht verwende, sondern einfach das locale objekt zurück gebe

C++:
Matrix::Matrix(int reihen, int spalten) {
    rowCount = reihen;
    columnCount = spalten;
    daten = new double*[reihen];
    for (int i = 0; i < reihen; i++) {
        daten[i] = new double[spalten];

    }
}

Matrix::Matrix(const Matrix& orig) {

    this->columnCount = orig.columnCount;
    this->rowCount = orig.rowCount;
    daten = new double*[orig.rowCount];
    for (int i = 0; i < orig.rowCount; i++) {
        daten[i] = new double[orig.columnCount];

    }

    for (int i = 0; i < orig.rowCount; i++) {

        for (int y = 0; y < orig.columnCount; y++) {

            daten[i][y] = orig.daten[i][y];

        }
    }

}

double Matrix::at(int row, int col)const {
    return daten[row][col];

}

Matrix Matrix::operator +(const Matrix& m) const {

    Matrix mTmp(m.columnCount, m.rowCount); //Hier verwende ich normalen Konstruktor, der oben ist    
                                                                            //und nicht den Kopierkonstruktor, da ich ein neues Objekt 
                                                                            //schaffen möchte und nichts kopieren
    if ((this->columnCount != m.columnCount) && (this->rowCount != m.rowCount)) {
        return mTmp;
    }

    mTmp.name = "locale AdditionsmatrixMatrix";
    for (int i = 0; i < this->rowCount; i++) {

        for (int y = 0; y < this->columnCount; y++) {

            mTmp.daten[i][y] = this->at(i, y) + m.at(i, y);

        }
    }

    return mTmp;
}


Matrix::~Matrix() {

    try {
        std::cout << this->name << "\n";
        for (int i = 0; i < this->rowCount; i++) {
            std::cout << daten[i] << "\n";
            delete[] daten[i];  //Hier kommt der Fehler, nach dem er beginnt das locale Objekt wieder  
                                         //freizugeben, ich kann auslesen, was an dieser Stelle gespeicher ist, aber diese
                                         //Stelle freizugeben, geht nicht, was mich verwirrt
        }
        delete[] daten;
    } catch (bad_alloc ex) {
        std::cout << "Fehler beim Freigeben: " << ex.what() << "\n";
    } catch (std::exception ec) {
        std::cout << "Fehler beim Freigeben2: " << ec.what() << "\n";

    } catch (...) {
        std::cout << "allgemeiner Fehler\n";
    }
}
 
Hallo,

den Copy Constructur brauchst du nicht explizit aufzurufen, das passiert automatisch bei "return mTmp;".

Ich sehe aber gerade, wenn du das so anwendest:
C++:
Matrix m1;
// ...
Matrix m2;
// ...

Matrix m3 = m1 + m2;
dann musst du noch den Operator für "=" überladen, damit das funktioniert.

Gruß
MCoder
 
Also ich bin immer noch der Meinung, dass du beim Operator Zeilen+Spalten vertauscht und daher beim Abbauen Fehler bekommst.

C++:
Obj* Obj::operator -(const Obj& m) const {
    Obj*mTmp = new Obj(m.columnCount, m.rowCount);
   
    ...
}
 
oh man...ja, du hast recht, obwohl ich noch mal drüber geschaut hab. Ich hab einfach nicht gesprüft ob ich im Konstruktor zuerst Zeilen oder Spalten erwarte....
jetzt geht alles, danke noch mal.
Welcher Ansatz wäre aber eleganter (oder es gibt andere Vorteile)??
1. In der Methode selbst im Heap ein Objekt erzeugen, und einen Zeiger zurück geben
2. Einfach ein local Objekt zurück geben
 

Neue Beiträge

Zurück