Segmentation fault in Destruktor

Hallo zusammen,

ich habe ein Problem mit einer selbst gebastelten Klasse „iTunesClass“,
die alle Stücke aus einer iTunes-XML ausliest und eine doppelt verkettete Liste aus Stücken im Speicher erstellt.

Wenn ich im Beispielprogramm eigenhändig „delete“ auf eine geladene Bibliothek anwende, scheint es so, als würde am Ende des Programmes alles noch einmal gelöscht werden, bzw. der Destruktor wird erneut aufgerufen. Der versucht dann Sachen zu löschen, die es gar nicht mehr gibt -> Segmentation fault.

Ich habe einen Foreneintrag gefungden ( http://bytes.com/topic/c/answers/826920-segmentation… ), in dem ein fehlender Copykonstruktor als mögliche Ursache gehandelt wird, was ich nicht so ganz verstehe. Was hat der Copykonstruktor mit dem Destruktor zu tun?

Ich poste erstmal keine Codeschnippsel, da das sehr lang und unübersichtlich wäre. (kann ich aber noch nachholen, wenns nötig wird)

Danke für eure Hilfe!

Arlecks

Hi,

kurze und knappe Regel: wenn deine Klasse etwas dynamisch allokiert (new) oder einen Zeiger verwaltet, der dann final in der Klasse freigegeben wird, dann muss ein Copy Constructor und ein Assignment Operator implementiert werden.

Ansonsten kann es sein, dass ein delete in einem Destruktor etwas versehentlich mehrfach löscht, nämlich dann, wenn nur dein interner Zeiger kopiert wurde.

Gruss
norsemanna

Danke für die Antwort,

nächste Frage: Warum? Wofür braucht der Destruktor sowas? Kannst du das genauer erläutern?

  1. Frage: Ich habe einfach mal deine Regel befolgt und sowohl Copykonstruktor als auch Zuweisungsoperatoren definiert. Funzt nicht. Jetzt kommen doch ein paar Schnippsel:

Das macht er wenn er ein neues Track-Objekt erstellt (Er geht die iTunes-XML schleifenweise durch):

if(entry == NULL) {
 entry = new Track;
 pointer = entry;
 pointer-\>previous = NULL;
} else {
 pointer-\>next = new Track;
 pointer-\>next-\>previous = pointer;
 pointer = pointer-\>next;
}
pointer-\>next = NULL;
pointer-\>mother = this;
++TrackCount;

Hier ist der Destruktor der Track-Klasse:

Track::~Track()
{
 if (this-\>previous != NULL)
 this-\>previous-\>next = this-\>next; //Fehler an dieser Stelle (siehe unten)
 if (this-\>next != NULL)
 this-\>next-\>previous = this-\>previous;
 if (mother != NULL)
 --(mother-\>TrackCount);
}

Die Fehlerausgabe:

Program received signal SIGSEGV, Segmentation fault.
At C:/Projects/iTunesClass/iTunesClass.cpp:337

Copykonstruktor und Zuweisungsoperator füge ich hier mal nicht ein, ich glaube nicht, dass da der Fehler liegt.

Arlecks

Hi,

nächste Frage: Warum? Wofür braucht der Destruktor sowas?
Kannst du das genauer erläutern?

Nicht der Destructor braucht das, dein Programm braucht das.
Copy Constructor und Assignment Operator sind unabhaengig vom Destructor.

Ist m_p eine Member Pointer Variable, dann kann diese - sofern du die oben genannten Sachen nicht hast- vorher einfach „by value“ mitkopiert worden sein, so dass du ein Objekt x und eine Kopie des Objekts y hast. Beide zeigen auf den nur einmal allokierten Bereich. Würde im destructor ein delete m_p stehen, so wuerdest du aber versuchen das Ganze mehr als einmal freizugeben.

Im uebrigen befindet sich in dem von dir geposteten Stueck Code kein explizites delete. Vielleicht solltest du doch ein paar mehr Codestuecke, inklusive dem Stueck, in dem sich das delete befindet, posten.

Gruss
norsemanna

Aber gerne doch:

  1. Beispielprogramm (der Konstruktor benutzt den Code aus dem letzten Post)

    int main(int argc, char *argv[])
    {
    iTunesLib Biblio(„c:\itunesganz.xml“);
    delete &Biblio;

    return EXIT_SUCCESS;
    }

  2. Destruktor iTunesLib

    iTunesLib::~iTunesLib()
    {
    struct Track *pointer = entry, *temp;
    while (pointer != NULL)
    {
    temp = pointer->next;
    delete pointer; //Hier!!
    pointer = temp;
    }
    }

  3. Private Methode in iTunesLib (wird von Copykonstruktor und Zuweisungsoperator genutzt)

    void iTunesLib::do_copy(const iTunesLib& temp)
    {
    Track *tracktemp, *pointer = temp.entry;

    this->filename = temp.filename;

    while (pointer != NULL)
    {
    tracktemp = new Track(*pointer);
    this->AddTrack(tracktemp);
    pointer = pointer->next;
    }
    }

  4. Das gleiche für Track (gekürzt)

    void Track::do_copy(const Track& temp)
    {
    Track_ID = temp.Track_ID;
    Name = temp.Name;
    Artist = temp.Artist;

    // usw.
    }

Das interessante ist, der Fehler tritt nur auf wenn ich die ca. 1400 Stücke mit diesem Konstruktor aus meiner Bibliothek lade. Wenn ich im Beispielprogramm 3 Track-Objekt erstelle und dann mit „AddTrack“ in die Bibliothek einfügen lasse, läuft es.

Dazu:

void iTunesLib::AddTrack(Track \*ctrack)
{
 if (entry != NULL)
 {
 struct Track \*pointer = entry;
 while (pointer-\>next != NULL)
 {
 pointer = pointer-\>next;
 }

 pointer-\>next = ctrack;
 ctrack-\>previous = pointer;

 } else {
 entry = ctrack;
 ctrack-\>previous = NULL;
 }
 ctrack-\>next = NULL;
 ctrack-\>mother = this;
 ++TrackCount;
}

Jetzt ist es doch sehr lang geworden. Danke für deine Hilfe!

Arlecks

Howdy,

  1. Beispielprogramm (der Konstruktor benutzt den Code aus dem
    letzten Post)

int main(int argc, char *argv[])
{
iTunesLib Biblio(„c:\itunesganz.xml“);
delete &Biblio;

return EXIT_SUCCESS;
}

fangen wir mal mit dem Offensichtlichen an. Dein Biblio ist kein dynamisch erzeugtes Objekt. D.h. man darf es nicht mit delete löschen. Es wird automatisch gelöscht, wenn es „out-of-scope“ fällt, in diesem Fall mit Ende der ‚}‘.

Gruss
norsemanna

Hallo ihr,

ich hatte mir vorgenommen, dass mir sowas nie passiert *haare rauf* :smiley:
Da sitzt man jahrelang vorm debugger und dann sowas… ich könnt mir selbst in die eier treten. Gibt’s einen Namen für solche Momente??
Naja…das muss ich erstmal verdauen.

DANKE, deine Geduld möchte ich haben :wink:
Gibs zu, du machst das doch auch nur um den Leuten hinterher beim in-die-Eier-Treten zuzugucken !

bis später…wenn du mal in der Situation bist… oder vergeht das mit der Zeit…?
Arlecks

Howdy,

könnt mir selbst in die eier treten. Gibt’s einen Namen für
solche Momente??
… oder vergeht das mit der Zeit…?

nein, nicht wirklich, man kann die Häufigkeit optimieren, aber ganz weg bekommt man das nicht :wink: Sprich: etwas Ähnliches passiert jedem Programmierer mit Regelmässigkeit ab und an …

Gruss
norsemanna