Frage bezüglich Heap Speicher

Freexer

Grünschnabel
Hallo,

habe mich in die letzen paar Tage in C++ ein bisschen eingearbeitet, habe schon mehrere Jahre in Java/PHP/C# programmiert, nur jetzt ist mir das mit dem Speicher Verwalten etwas neu.

Ich habe gelesen das ich alles manuell löschen muss was ich im Heap alloiziere nur jetzt habe ich keine Ahnung mit welchen Methoden ich was im Heap alloizieren kann.

Von den unten genanten Methode weiß ich das ich das Objekt wieder von Hand löschen muss.

Klasse * name = new Klasse
name->blablup();
delete name;

Ne Klasse inizalisier ich ja normal mit "Klasse name;" wenn ich aber aus name nen Zeiger mache "Klasse * name;" um mit dem Operator -> zugreifen zu können wird das dann auch im Heap inizalisiert/Speicher im Heap reserviert und ich muss es dann löschen ?

Bin mir da etwas unsicher deshalb frag ich mal lieber nach nicht das ich nachher haufenweiße Memory Leaks im Programm habe.
 
Alles, was mit new erzeugt wird, wird auf dem Heap abgelegt. new ist nichts anderes als ein Operator, der malloc implizit aufruft. Daher müssen Objekte auch mit delete entfernt werden. Dabei ist delete nichts anderes als eine Implementierung von free().
Wenn man also eine Zeiger-Variable anlegt, ist das ja zunächst nur ein 2 Byte breiter Speicherbereich, der eine Adresse beinhalten kann.
C++:
char *s;

Dieser Zeiger s zeigt derzeit auf keinen gültigen Speicherbereich, wir gehen also davon aus, er ist NULL. Mit malloc(size_t) reservierst du nun Speicher beim Betriebssystem. Der Speicher wird auf dem Heap gesucht, und zwar mit der Größe size_t. Wenn ein Speicherbereich gefunden wird, wird dieser getaggt und anschließend die Adresse als void* zurück gegeben. Diese Adresse kann nun dem Zeiger s zugewiesen werden. Dadurch das der Speicher getaggt wird, kann kein anderer Prozess diesen Speicher erneut bekommen. Wenn der Speicherbereich nach Beendigung des Prozesses, der den Speicher angefordert hat, immer noch getaggt ist, kann ihn praktisch nie wieder jemand bekommen, bis das Betriebssystem neu gestartet wurde. Daher muss man den Tag mittels free() wieder entfernen. Tut man es nicht, hat man ein sog. Memory Leak oder zu deutsch Speicherleck.

Das gilt also für alle Objekte und Variablen, die mit malloc()/realloc() oder new erzeugt wurden.

Wenn du allerdings sowas machst:

C++:
                                                                                                                                                                                                                                                                                 char foo[20];
 strcpy(foo, "Hello World");
 char *bar = foo[5];   // << hier zeigt bar jetzt auf das Leerzeichen

darfst du bar natürlich nicht freigeben. Das ist zwar auch ein Zeiger, aber für den wurde kein Speicher auf dem Heap reserviert. Der zeigt nur lustig auf den Bereich einer Variablen auf den Stack. free() wäre hier fatal.

Sorry, wenn ich das jetzt etwas ausführlicher geschrieben habe, ich denke aber, das es dich weiter bringt.
 
Kurz zusammen gefasst hätte es auch gereicht aber vielen Dank erstmal. So wie dus geschrieben hast wusst ich es auch aber ich mir nicht ganz sicher.

Also wenn ich jetzt ein Objekt mit
C++:
Menschen *menschenObj;
menschenObj->setName("Hallo");
also ohne new inizalisiere muss ich nachher nichts wieder feigeben außer ich setze noch ein = new Menschen(); dahinter, sehe ich das richtig ?
 
Zuletzt bearbeitet von einem Moderator:
Wenn man also eine Zeiger-Variable anlegt, ist das ja zunächst nur ein 2 Byte breiter Speicherbereich, der eine Adresse beinhalten kann.
Die Größes eines Zeigers ist allerdings von der Plattform abhängig. Auf 32-Bit-Systemen ist ein Zeiger z.B. in der Regel 4 Byte groß.

Dieser Zeiger s zeigt derzeit auf keinen gültigen Speicherbereich, wir gehen also davon aus, er ist NULL.
Nur damit keine Missverständnisse aufkommen: der Wert einer uninitialisierten Variable ist undefiniert. Das heißt, dass man nicht davon ausgehen kann, dass ein uninitialisierter Zeiger ein Nullzeiger ist. Ebensowenig kann man sagen, dass er auf einen ungültigen (nicht reservieren) Speicherbereich zeigt.

Wenn der Speicherbereich nach Beendigung des Prozesses, der den Speicher angefordert hat, immer noch getaggt ist, kann ihn praktisch nie wieder jemand bekommen, bis das Betriebssystem neu gestartet wurde.
Das ist Unsinn, zumindest wenn das Betriebssystem mit virtueller Speicherverwaltung arbeitet. Wenn ein Prozess beendet wird, wird sämtlicher ihm zugeordneter Speicher freigegeben. Speicherlecks sollten aber natürlich trotzdem vermieden werden.

Grüße, Matthias
 
Also wenn ich jetzt ein Objekt mit
C++:
Menschen *menschenObj;
menschenObj->setName("Hallo");
also ohne new inizalisiere muss ich nachher nichts wieder feigeben außer ich setze noch ein = new Menschen(); dahinter, sehe ich das richtig ?
Nein, hier musst du nichts freigeben. Die Frage stellt sich aber auch überhaupt nicht, da das Verhalten deines Programms in der zweiten Zeile undefiniert ist. Du versuchst hier nämlich, einen nicht initialisierten Zeiger zu dereferenzieren.

Grüße, Matthias
 
Zuletzt bearbeitet von einem Moderator:
C++:
Menschen *menschenObj;
menschenObj->setName("Hallo");

Also so geht das gar nicht ?


C++:
Menschen *menschenObj = new Menschen();
menschenObj->setName("Hallo");
delete menschenObj;

so gehts aber ?
 
Zuletzt bearbeitet von einem Moderator:
Die Größes eines Zeigers ist allerdings von der Plattform abhängig. Auf 32-Bit-Systemen ist ein Zeiger z.B. in der Regel 4 Byte groß.

Korrekt, kann mir grad auch nicht erklären, warum ich 2 geschrieben habe.

Nur damit keine Missverständnisse aufkommen: der Wert einer uninitialisierten Variable ist undefiniert. Das heißt, dass man nicht davon ausgehen kann, dass ein uninitialisierter Zeiger ein Nullzeiger ist. Ebensowenig kann man sagen, dass er auf einen ungültigen (nicht reservieren) Speicherbereich zeigt.
Das war mir auch klar, ich wollte es nur etwas plastisch darstellen.

Das ist Unsinn, zumindest wenn das Betriebssystem mit virtueller Speicherverwaltung arbeitet. Wenn ein Prozess beendet wird, wird sämtlicher ihm zugeordneter Speicher freigegeben. Speicherlecks sollten aber natürlich trotzdem vermieden werden.

Ja, laut wikipedia und anderen Quellen kenn ich das auch so. Allerdings wunder ich mich immer wieder, wenn ich mit Speicher-Check-Tools wie valgrind anwende und solche Dinge lese wie, "so-und-so-viel Byte unwiderbringlich verloren". Was heißt das denn dann genau?
 
C++:
Menschen *menschenObj;
menschenObj->setName("Hallo");

Also so geht das gar nicht ?
Richtig.
C++:
menschenObj->setName("Hallo");
ist nur eine verkürzende Schreibweise für
C++:
(*menschenObj).setName("Hallo");
, also einer Dereferenzierung des Zeigers gefolgt von einem Methodenaufruf. menschenObj wurde zu dem Zeitpunkt allerdings nicht initialisiert, d.h. der Zeiger zeigt auf irgendeinen mehr oder weniger zufälligen Speicherbereich, der mit an Sicherheit grenzender Wahrscheinlichkeit weder reserviert noch mit einer Instanz der Klasse Menschen gefüllt ist. Das Verhalten bei der Dereferenzierung eines uninitialisierten Zeigers ist undefiniert, wobei ein sofortiger Programmabsturz (z.B. durch eine Speicherschutzverletzung) noch der beste Ausgang einer solchen Aktion ist.
C++:
Menschen *menschenObj = new Menschen();
menschenObj->setName("Hallo");
delete menschenObj;

so gehts aber ?
Korrekt. Hier sorgt new dafür, dass erstens genügend Speicher für die Instanz auf dem Heap reserviert wird und zweitens, dass der Konstruktor aufgerufen wird. menschenObj zeigt jetzt also auf einen reservierten Speicherbereich auf dem Heap, in dem eine fertig initialisierte Instanz von Menschen abgelegt ist. Der Dereferenzierung und dem Methodenaufruf steht somit nichts mehr im Wege.

Das war mir auch klar, ich wollte es nur etwas plastisch darstellen.
Dass es dir klar ist, war mir auch klar ;) Wie gesagt: die Anmerkung war nur dazu gedacht, Missverständnissen bei anderen Lesern hier vorzubeugen.

Ja, laut wikipedia und anderen Quellen kenn ich das auch so. Allerdings wunder ich mich immer wieder, wenn ich mit Speicher-Check-Tools wie valgrind anwende und solche Dinge lese wie, "so-und-so-viel Byte unwiderbringlich verloren". Was heißt das denn dann genau?
Das „unwiederbringlich“ bezieht sich hier vermutlich auf die aktuelle Programmausführung. Valgrind erkennt, dass es keine Zeiger mehr auf einen reservierten Speicherbereich gibt und meldet ihn somit als „verloren“.

Grüße, Matthias
 
Zuletzt bearbeitet von einem Moderator:
Zurück