Forum: PC-Programmierung Destruktor - wann und wie wird Speicher freigegeben?


von Lars w. (Gast)


Lesenswert?

Hallo Community,

ich habe vorher nur mit Java zu tun gehabt, deshalb verwirrt mich die 
manuelle Speicherfreigabe / Objektlöschung noch ein bisschen.

Ich habe mir eine kleine Test-Klasse geschrieben. Am Ende kann  ich 
sehen, dass der Destruktor aufgerufen wurde. Die frage die ich mir jetzt 
stelle - reicht das? Weil ich immer wieder in Online-Quelltexten sehe, 
dass im Destruktor noch mit delete gearbeitet wird. Muss ich die ganzen 
angelegten varaiblen innerhalb eines Objektes noch mit delete löschen 
lassen, bevor dann die Referenu auf das Objekt durch den Destruktor 
gelöscht wird?

Viele Grüße :) !

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Lars w. schrieb:
> Muss ich die ganzen
> angelegten varaiblen innerhalb eines Objektes noch mit delete löschen
> lassen,

Wenn die Variablen jeweils mit new angelegt wurden, ja. Zu jedem new 
gehört ein korrespondierendes delete.

von Maxim (maxim) Benutzerseite


Lesenswert?

Wenn du Member mit new erzeugst, musst du sie im Destruktor mit delete 
zerstoeren. Fuer solche mit new[] wird delete[] genommen. Fuer malloc 
oder calloc wird free() genommen.

von Sven B. (scummos)


Lesenswert?

Wie immer kann ich hier raten: Schau' dir mal an, was valgrind zu deinem 
Programm sagt. Das ist immer sehr interessant -- in Fall von Memory 
Leaks hast du was falsch gemacht, wenn am Schluss nicht "definitely 
lost: 0" da steht. ;)

Grüße,
Sven

von Lars w. (Gast)


Lesenswert?

Vielen Dank euch ! Leuchtet alles ein. Und valgrind klingt super - kennt 
da jemand was äquivalentes zu Windows?

von Yalu X. (yalu) (Moderator)


Lesenswert?

Valgrind für Windows ist in Arbeit, scheint aber noch sehr frisch zu
sein:

  http://sourceforge.net/projects/valgrind4win/

Hier sind ein paar Vorschläge für Ersatzlösungen:

  http://stackoverflow.com/questions/413477/is-there-a-good-valgrind-substitute-for-windows

von Lars w. (Gast)


Lesenswert?

VIelen Dank !

Ich hab mir jetzt Dr.Memory geladen. Dadurch konnte ich schon 2 
Speicherleaks in meinem Programm beheben (eben Aufgrund des vergessenen 
Deletes bei dynamisch angelegten Speicher per new...).

Ich bin total begeistert ^^

von Sven B. (scummos)


Lesenswert?

Oft ist auch manuelles Speichermanagement in C++ nicht ideal. Das lohnt 
sich nur in manchen Fällen. Es gibt noch weitere Möglichkeiten:
* shared pointer -- macht reference counting. Das hat natürlich einen 
gewissen Overhead, ist aber in vielen Fällen egal. Dafür garantiert 
diese Methode, dass das Objekt gelöscht wird, genau dann wenn es 
nirgends mehr benutzt wird.
* scoped pointer -- wenn man Objekte nur mit "new" anlegt, weil sie zu 
groß sind für den Stack, ist das die richtige Methode
* memory pools -- wenn man viele kleine Allokationen braucht, die alle 
gemeinsam wieder freigegeben werden sollen, ist das oft auch eine gute 
Idee.

Die stdlib hat diverse pointer-Klassen für sowas.

Grüße,
Sven

von Lars w. (Gast)


Lesenswert?

Danke dir Sven, auch das werde ich mir anschauen :)

Lg

von Rolf M. (rmagnus)


Lesenswert?

Und dann ist natürlich noch zu erwähnen, daß man Objekte oft gar nicht 
mit new anlegen muß. Wenn man aus der Java-Ecke kommt, ist das ja nicht 
selbstverständlich. Es gibt in C++ drei Arten von Speicher, nämlich 
statisch, dynamisch und automatisch, und Instanzen jedes Datentyps 
können auf jede dieser drei Arten erzeugt werden, egal ob es sich um 
Klassen oder eingebaute Typen handelt.
Dabei leben "statische" Objekte bis zum Programm-Ende und werden dann 
zerstört, "automatische" Objekte sind lokale Variablen, die beim 
Verlassen des Blocks, in dem sie definiert sind, zerstört werden, und 
"dynamische" Objekte sind die, die mit new angelegt wurden. Diese (und 
nur die) müssen mit delete explizit zerstört werden.

von Karl H. (kbuchegg)


Lesenswert?

Rolf Magnus schrieb:
> Und dann ist natürlich noch zu erwähnen, daß man Objekte oft gar nicht
> mit new anlegen muß. Wenn man aus der Java-Ecke kommt

Rolf hat absolut recht.
Gerade die Leute aus der Java oder C# Ecke tendieren dazu, viel zu viel 
mittels new anzulegen, weil sie das von Java/C# so gewohnt sind. Dabei 
muss man in C++ viel weniger mittels new allokieren und wenn tatsächlich 
mal etwas dynamisch allikiert werden muss, dann ist man mit den 
Containern der STL oft (aber nicht immer) besser bedient.

Und auch immer an die 'Rule of three' denken: Benötigt man unbedingt 
eine der 3 Funktionen Destruktor, Copy Constructor oder 
Assignment-Operator, dann benötigt man meistens alle 3.
Macht man selbst dynamisches Memory Management, dann benötigt man auf 
jeden Fall alle 3. Selbst wenn 2 davon (CCtor und Op=) lediglich so 
trivial verpackt werden, dass sie für Compiler/Linker nicht benutzbar 
sind und daher jeder Versuch sie einzusetzen zu einem Compiler/Linker 
Fehler führt, der Schlimmeres zur Laufzeit verhindert.

von Steffen (Gast)


Lesenswert?

Hallo Karl Heinz,

Karl Heinz Buchegger schrieb:
> Dabei
> muss man in C++ viel weniger mittels new allokieren und wenn tatsächlich
> mal etwas dynamisch allikiert werden muss, dann ist man mit den
> Containern der STL oft (aber nicht immer) besser bedient.

Ich tendiere eher umgekehrt: Sie sollten alle nicht-Primitive mit 
new/(boost::)shared_ptr anlegen (soweit möglich)...

> Macht man selbst dynamisches Memory Management, dann benötigt man auf
> jeden Fall alle 3. Selbst wenn 2 davon (CCtor und Op=) lediglich so
> trivial verpackt werden, dass sie für Compiler/Linker nicht benutzbar

...genau, c'ctor und op= lediglich deklarieren um deren (versehentliche) 
Nutzung auszuschließen.

Das hat den Vorteil, sie können "normal" weiter programmieren wie bisher 
und die (meist) unnötigen (und manchmal auch fehlerhaften) Objektkopien 
entfallen. Vor einer op= Zuweisung in C++ wird imho viel weniger 
nachgedacht als vor einem copy/clone.

Grüße, Steffen

von Karl H. (kbuchegg)


Lesenswert?

Steffen schrieb:
> Hallo Karl Heinz,
>
> Karl Heinz Buchegger schrieb:
>> Dabei
>> muss man in C++ viel weniger mittels new allokieren und wenn tatsächlich
>> mal etwas dynamisch allikiert werden muss, dann ist man mit den
>> Containern der STL oft (aber nicht immer) besser bedient.
>
> Ich tendiere eher umgekehrt: Sie sollten alle nicht-Primitive mit
> new/(boost::)shared_ptr anlegen (soweit möglich)...

Sofern eine dynamische Allokierung überhaupt notwendig ist - das ist der 
springende Punkt auf den ich raus will.

von Lars w. (Gast)


Lesenswert?

Hallo nochmal,

vielen Dank für die weiteren Hinweise, ich denke, ich habe es jetz 
verstanden. Ich versuche auch möglichst nicht mi new* o.ä zu arbeiten. 
Allerdings benötige ich für ein kleines Spiel ein dynamisches Array, 
daher bin ich darauf gekommen.

von Karl H. (kbuchegg)


Lesenswert?

Lars w. schrieb:
> Hallo nochmal,
>
> vielen Dank für die weiteren Hinweise, ich denke, ich habe es jetz
> verstanden. Ich versuche auch möglichst nicht mi new* o.ä zu arbeiten.
> Allerdings benötige ich für ein kleines Spiel ein dynamisches Array,
> daher bin ich darauf gekommen.

std::vector ist dein Freund.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.