Frage zu Destruktor



  • Hey!

    Ich hab mal zwei Fragen was Objekte betrifft.

    1. Wie ihr ja sicher wisst, hat Java einen automatischen GarbageCollector, den man nicht beeinflussen kann. C++ hat das ja aber nicht, man kann mit "delete" Objekte zerstören.

    Jetzt meine Frage: Ist das bei Objekten so, die auf dem Heap und dem Stack sind so, oder nur bei den Heap-Objekten (da sie ja auch mit new erstellt wurden).

    2. Wie sieht denn so ein typischer Destruktor aus. Man möchte ja bspw. den Speicherplatz der zerstörten Variablen wieder freigeben. Wie mache ich das?

    Danke!!



  • Nur was du mit new anforderst musst du auch mit delete wieder freigeben. Alles andere passiert "automatisch". Also verzichte weitestgehend auf new , damit du kein delete vergisst. Ansonsten hilft ein gutes Buch.



  • Dass würde also bedeuten, dass C++ bei Objekten, die auf dem Stack (also nicht mit new angelegt wurden) liegen, einen automatischen GarbageCollecor haben? Also ähnlich wie Java?!


  • Mod

    blub85 schrieb:

    1. Wie ihr ja sicher wisst, hat Java einen automatischen GarbageCollector, den man nicht beeinflussen kann. C++ hat das ja aber nicht, man kann mit "delete" Objekte zerstören.

    C++ hat etwas, was die C+'ler viel toller finden: Automatische Stackverwaltung. Du braucht new und delete fast nie. Und wenn, dann versteckst du sie in Klassen, die dann auf dem Stack liegen und so von der automatischen Verwaltung profitieren, siehe unten.

    Jetzt meine Frage: Ist das bei Objekten so, die auf dem Heap und dem Stack sind so, oder nur bei den Heap-Objekten (da sie ja auch mit new erstellt wurden).

    Mit delete kannst und musst du genau die Objekte zerstören, die du mit new erzeugt hast. delete ist zudem kein direkter Destruktoraufruf sondern gibt zudem auch noch den Speicher der mit new angefordert wurde wieder frei. Es ist möglich aber nur sehr sehr selten sinnvoll, einen Destruktor direkt aufzurufen, meistens im Zusammenhang mit einem placement new.

    Wie oben schon gesagt, ist wahrscheinlich an deinem Design etwas falsch, wenn du diese Antwort wirklich brauchtest.

    .

    2. Wie sieht denn so ein typischer Destruktor aus. Man möchte ja bspw. den Speicherplatz der zerstörten Variablen wieder freigeben. Wie mache ich das?

    Typischerweise schreibst du überhaupt gar keinen Destruktor. Der Compiler schreibt dann automatisch einen Destruktor der äquivalent zu dem Destruktor ist, den du mit einer leeren Destruktorfunktion erhalten hättest. Du musst auch im Destruktor nicht den Speicherplatz von den Membern freigeben. Die Destruktoren von Membern werden automatisch rekursiv allesamt aufgerufen, in umgekehrter Reihenfolge wie sie erzeugt wurden. Das kannst du auch überhaupt nicht verhindern, selbst wenn du es wolltest.

    Der Fall, wo man einen nicht-leeren Destruktor hat ist, wenn die Klassen irgendwelche Arten von Ressourcen verwaltet, die wieder freigegeben werden müssen. Meistens sind das Variablen auf dem Heap, aber auch Socketverbindungen oder Dateihandles (aber keine fstreams oder vectoren oder ähnliches! Die machen das schon selber in ihrem Destruktor. Da, wie oben erklärt, sowieso deren Destruktor aufgerufen wird, musst du dich darum nicht mehr kümmern!). Dann werden diese im Destruktor explizit freigegeben.

    Zwei Googlestichworte: RAII, Regel der großen Drei

    Komm als jemand der von Java kommt bloß nicht auf die Idee, in C++ wie in Java zu programmieren. Faustregeln:
    - Alles auf dem Stack, außer man hat sehr gute Gründe dagegen.
    - new und delte sind verdächtig
    - new[] und delete[] sind falsch, das ist std::vector.
    - Das RAII möglichst in die untersten Glieder der Memberkette fortsetzen. Eine Klasse verwaltet nicht mehrere Pointer und macht auf diesen new und delete, sie benutzt stattdessen smartpointer die das jeder getrennt für sich machen. Sie hält keine Dateihandles die manuell geschlossen werden müssen, sie halt eine Klasse (z.B. fstream aus der Standardbibliothek), die das selber machen. Folglich sind nur die Destruktoren der Klassen in der untersten Ebene nicht-trivial.



  • Okay, VIELEN VIELEN DANK!!! DU BIST MIR EINE SEHR GROSSE HILFE!

    Ich hab das jetzt soweit verstanden. Jetzt eine Frage, die wahrscheinl. recht häufig kommt: Wann Sack und wann Heap?

    Im Normalfall, so schreibst Du ja, solle man eher den Stack benutzen, ne?

    D a n k e!



  • Nutze doch erstmal den Stack. Wenn du dann an eine Stelle kommst, an der du denkst, dass sich ein new nicht vermeiden lässt, fragste noch mal nach. 🙂



  • Hehe 😉 🙂

    Es ist aber so, dass ich bald ne Diplomprüfung in Informatik habe, bei der ich mich -zumindest theoretisch- mit C++ auskennen muss.

    Vond aher meine Frage. 😉


  • Mod

    Ganz allgemein braucht man den Heap genau in zwei Fällen:
    - Die Größe des Datenobjekts steht zur Compilezeit nicht fest. Dies kann zum Beispiel sein, wenn von einer Benutzereingabe abhängt, wie viele Objekte erzeugt werden oder von welchem Typ sie genau sind. Besonders das erste Problem hat man sehr häufig, praktisch in jedem Programm.
    - Man hat technische Beschränkungen für die Stackgröße und die Objekte passen nicht drauf.

    In beiden Fällen wird man aber seltenst new und delete selbstständig machen. Die C++ Standardbibliothek hat bereits alle wichtigen Fälle mit passenden Verwaltungsobjekten (im Prinzip meistens bloß Pointer mit Programmlogik dahinter) abgedeckt. Die Verwaltungsobjekte liegen dann auf dem Stack und werden dort automatisch abgeräumt wenn sie ihren Gültigkeitsbereich verlassen und räumen ihre Heapdaten dann mit auf. Für den seltenen Fall, dass die Standardbibliothek nicht bietet was man braucht, sollte man aber mindestens dieses bewährte Konzept benutzen und eigene Verwaltungsobjekte schreiben.



  • Du hast Polymorphie vergessen.



  • Wo braucht man denn bei Polymorphie den Heap? 😕


  • Mod

    314159265358979 schrieb:

    Du hast Polymorphie vergessen.

    Doch, den Fall wo du für Polymorphie den Heap brauchst:

    Seppj schrieb:

    oder von welchem Typ sie genau sind

    Bashar schrieb:

    Wo braucht man denn bei Polymorphie den Heap? 😕

    Genau. Wenn du vorher schon weißt, welche und wie viele Objekte eines Typs du hast, dann kannst (und solltest) du sie auch auf dem Stack polymorph ansprechen.


Anmelden zum Antworten