Speicher Allokation



  • Hallo,

    ich habe eine grundsätzliche Frage zur dynamischen Speicherallokation.

    //statische Speicher Allokation	
    	int a;
    	a = 15;
    
    	//dynamische Speicher Allokation
    	int* Pb;		
    	Pb = new int;
    	*Pb = 20;
    

    Ich habe mir mal Folgendes zusammengegoogelt:
    In der statischen Speicher Allokation wird das Objekt auf dem Stack angelegt, in der dynamischen Speicher Allokation wird das Objekt auf dem Heap angelegt. Der Heap ist ein viel Grösserer Speicherbereich als der Stack. Der Stack funktioniert nach dem "first in, last out" -Prinzip. Beim Stack ist dies offenbar nicht der Fall.

    Was ich nicht verstehe ist dies:
    Ich lese immer wieder, dass beim statischen Speicher die Objekte zur Compile-Zeit angelegt werden, und das Heap-Objekte erst zur Ausführungszeit angelegt werden.
    Ich versteht nicht, was das genau zu bedeuten hat.
    Muss nicht jedes Objekt zur Compile-Zeit angelegt werden? Wenn ich den Quellcode kompiliere, dann werden die Objekte doch einfach angelegt - egal ob auf dem Heap oder auf dem Stack.

    Ich wäre sehr froh wenn mir jemand einen Tipp geben könnte, was genau mit dynamischer Speicher-Allokation gemeint ist, bzw. wo mein Überlegungsfehler liegt.

    Ich muss wohl nicht mehr speziell erwähnen, dass ich Programmieranfänger bin.

    Vielen Dank für alle Antworten
    Benu


  • Mod

    Benu schrieb:

    Was ich nicht verstehe ist dies:
    Ich lese immer wieder, dass beim statischen Speicher die Objekte zur Compile-Zeit angelegt werden, und das Heap-Objekte erst zur Ausführungszeit angelegt werden.

    Angelegt ist hier wohl der falsche Ausdruck. Wirklich entstehen tun die Objekte auch erst zur Laufzeit. Aber bei Stackobjekten steht zur Compilezeit genau fest, wie viele und welche Art von Objekten in einer Funktion vorhanden sind. Bei dynamischen Objekten braucht dies nicht der Fall zu sein. Da kann man zur Laufzeit entscheiden (zum Beispiel nach Benutzereingabe), wie viele Objekte von welcher Art man benötigt.

    Beispiel:

    int main()
    {
      unsigned int anzahl;
      cin >> anzahl;
      int foo[anzahl];   // Geht nicht
    }
    
    int main()
    {
      unsigned int anzahl;
      cin >> anzahl;
      unique_ptr<int[]> foo(new int[anzahl]);  // Geht
    }
    

    Noch ein paar Bemerkungen zu den Beispielen:
    - Der erste Quelltext geht auch, auf dem verbreiteten Gnu Compiler (GCC), der dies als spezielles Feature unterstüzt (abschaltbar, aber standardmäßig aktiviert). Also nicht verwirren lassen, falls es doch funktioniert.
    - Im zweiten Quelltext würde man natürlich nie new für Arrays benutzen, sondern std::vector. Wollte nur deutlicher machen, dass dort der Heap benutzt wird.
    - Im zweiten Quelltext lebt der Zeiger foo selber auch auf dem Stack. Das Objekt, auf das er zeigt, also das mit new erzeugte (namenlose) Array, ist auf dem Heap.



  • Benu schrieb:

    In der statischen Speicher Allokation wird das Objekt auf dem Stack angelegt, in der dynamischen Speicher Allokation wird das Objekt auf dem Heap angelegt. Der Heap ist ein viel Grösserer Speicherbereich als der Stack. Der Stack funktioniert nach dem "first in, last out" -Prinzip. Beim Stack ist dies offenbar nicht der Fall.

    Im letzten Satz meinst du Heap.

    Ich lese immer wieder, dass beim statischen Speicher die Objekte zur Compile-Zeit angelegt werden, und das Heap-Objekte erst zur Ausführungszeit angelegt werden.

    Das ist völliger Unsinn. Es stimmt, das eingecodet wird, wie der Stack beim function prologue verändert wird um Platz für alle Stackvariablen zu machen. Aber erzeugt werden die Objekte erst, wenn du das Programm ausführst.

    Ich versteht nicht, was das genau zu bedeuten hat.

    Gar nichts, vergiss diesen Blödsinn.

    Muss nicht jedes Objekt zur Compile-Zeit angelegt werden?

    Hä?

    Wenn ich den Quellcode kompiliere, dann werden die Objekte doch einfach angelegt - egal ob auf dem Heap oder auf dem Stack.

    Nein!?

    Ich wäre sehr froh wenn mir jemand einen Tipp geben könnte, was genau mit dynamischer Speicher-Allokation gemeint ist, bzw. wo mein Überlegungsfehler liegt.

    dynamic storage duration heißt, dass der Speicher erst wieder freigegeben wird, wenn du ihn explizit mit delete freigibst. automatic storage duration sichert ab, dass die Objekte beim Verlassen des Scopes in dem sie deklariert worden sind zerstört werden. Andere Variablen (globale, als static deklarierte) haben static storage duration. Bringe also statisch und dynamisch nicht durcheinander, besonders weil hier auch noch OOP im Spiel sein kann (statische bzw. dynamische Bindung...).

    Also nicht verwirren lassen, falls es doch funktioniert.

    Hallo, C++14, §8.3.4/1? 😉



  • Hallo,

    Vielen Dank für die Antworten. Ich glaube ich habs jetzt verstanden. Ich wäre trotzdem froh, wenn mir dies noch jemand durchlesen könnte.

    int a;
    

    a wird auf dem Stack abgelegt. Wenn der Scope verlassen wird, dann wird a automatisch gelöscht.
    Bei Stack-Objekten muss zur Compile-Zeit bekannt sein, wie viele und welche Objekte existieren.

    static int b;
    

    b wird im globalen Speicher abgelegt. Das heisst, wenn b einmal deklariert ist, dann lebt es während der ganzen Laufzeit des Programms.
    Bei static Variablen muss zur Compile-Zeit bekannt sein, wie viele und welche Objekte davon existieren.

    int *c = new int[x];
    

    c wird auf dem Heap abgelegt. B muss von Hand mit delete gelöscht werden.
    Heap-Objekte sind die einzigen Objekte, bei denen während der Laufzeit festgelegt werden kann, wie gross sie sind.

    Ist dies so richtig? Vielen Dank fürs Durchlesen und Antworten 🙂

    Benu



  • Nicht ganz. c liegt auch am Stack, aber das Array, auf das der Zeiger zeigt, am Heap.



  • Benu schrieb:

    int a;
    

    a wird auf dem Stack abgelegt. Wenn der Scope verlassen wird, dann wird a automatisch gelöscht.
    Bei Stack-Objekten muss zur Compile-Zeit bekannt sein, wie viele und welche Objekte existieren.

    Richtig. Wobei ich sagen würde: a wird im automatischen Speicher abgelegt, und der automatischen Speicher ist als ein Stack implementiert.

    Benu schrieb:

    static int b;
    

    b wird im globalen Speicher abgelegt. Das heisst, wenn b einmal deklariert ist, dann lebt es während der ganzen Laufzeit des Programms.
    Bei static Variablen muss zur Compile-Zeit bekannt sein, wie viele und welche Objekte davon existieren.

    Nicht im globalen Speicher, sondern im statischen Speicher. Im statischen Speicher landen static-qualifizierte Objekte, globale Objekte und auch Zeichenkettenliterale.

    Benu schrieb:

    int *c = new int[x];
    

    c wird auf dem Heap abgelegt. B muss von Hand mit delete gelöscht werden.
    Heap-Objekte sind die einzigen Objekte, bei denen während der Laufzeit festgelegt werden kann, wie gross sie sind.

    Fast. Der Zeiger c wird im automatischen Speicher abgelegt. Der int wird im dynamischen Speicher (Heap) abgelegt. Ja, mit new/new[] erzeugte Objekte müssen manuell mit delete/delete[] gelöscht werden (das ist doof und fehleranfällig, darum verwenden wir es fast nie).



  • Nur noch zur Differenzierung der Begriffe:

    automatischer Speicher = Stack
    statischer Speicher = globale/statische Variablen



  • klarsteller schrieb:

    automatischer Speicher = Stack
    statischer Speicher = globale/statische Variablen

    Richtig. Wie gesagt, landen Zeichekettenliterale auch im statischen Speicher:

    const char* p = "Hallo Welt"; // p liegt im automatischen Speicher. "Hallo Welt" liegt im statischen Speicher.
    


  • Bzw.: automatischer Speicher = Stack = lokale Objekte


Anmelden zum Antworten