Heap oder Stack



  • Kann mir jemand sagen, ob der Vector in A auf dem Heap oder Stack angelegt wird. a wird ja auf dem Heap durch new angelegt, aber vec in A wird ja nicht per new angelegt, sondern als Initmember. Ist vec nun, weil er ja Memeber von a ist und der auf dem Heap lebt, automatisch auch auf dem Heap?

    #include <vector>
    
    struct A
    {
    	std::vector<int> vec{};	
    };
    
    int main()
    {
    	A *a = new A; // a.vec Heap oder Stack?
    	delete a;
    }
    


  • Ich wurde sagen auf dem Heap, da bei structs die Member hintereinander im Speicher gespeichert sind.



  • Ja



  • Ein vector speichert seinen Inhalt sowieso auf dem Heap. Das new betrifft nur seine 12 Verwaltungsbytes.



  • Und wie sieht es aus, wenn vec nun kein std::vector wären, sondern irgend ein eigenes Objekt?

    #include <vector>
    
    struct A
    {
        myObjekt obj{};
    };
    
    int main()
    {
        A *a = new A; // a->obj Heap oder Stack?
        delete a;
    }
    


  • Der einzige Unterschied zwischen struct und class ist doch bloß die Standaed-Sichtbarkeit, also im Falle von struct immer public und bei class immer privat, oder? Das hat doch keinen Einfluss darauf wie in C++ Objekte angelegt werden, oder?


  • Mod

    HeapStacker schrieb:

    Der einzige Unterschied zwischen struct und class ist doch bloß die Standaed-Sichtbarkeit, also im Falle von struct immer public und bei class immer privat, oder? Das hat doch keinen Einfluss darauf wie in C++ Objekte angelegt werden, oder?

    Korrekt.

    Und wie sieht es aus, wenn vec nun kein std::vector wären, sondern irgend ein eigenes Objekt?

    Warum sollte das einen Unterschied machen? Ein vector ist ein Objekt wie jedes andere. Die 3 schon gegebenen Antworten gelten also auch weiterhin.



  • IBV schrieb:

    Ich wurde sagen auf dem Heap, da bei structs die Member hintereinander im Speicher gespeichert sind.

    Also ist diese Vermutung und diese Aussage richtig? Die Aussage impliziert doch, dass es noch mehr Unterschiede zwischen struct und class gibt als die Sichtbarkeit. So unter dem Motto, bei class liegen eben die Member nicht hintereinander im Speicher wie bei struct.

    Was ist mit den Verwaltungsbytes, so wie sie hier genannt wurden, wo leben die? Ich will doch bloß klipp und klar wissen wo alles liegt, wenn ich ein Objekt anlege. Gibt es da keine Seite, außer dem Standard, wo ich das nachlesen kann. Oder kann ich das auch mit dem Debugger raus finden.

    Direkte Antworten würden mir mehr helfen als indirekte, wie "wurde schon gesagt" oder "googel doch".



  • Wenn Du etwas mit new erzeugst, lebt es auf dem Heap, und zwar vollständig. Automatische Variablen leben auf dem Stack, aber wenn es sich dabei um Instanzen von Structs/Klassen handelt, können diese natürlich wieder Member enthalten, die Speicher vom Heap anfordern (zB. vector).
    Ausnahmen sind statische Variablen, die leben afaik immer im Datensegment des Lademoduls.


  • Mod

    HeapStacker schrieb:

    IBV schrieb:

    Ich wurde sagen auf dem Heap, da bei structs die Member hintereinander im Speicher gespeichert sind.

    Also ist diese Vermutung und diese Aussage richtig? Die Aussage impliziert doch, dass es noch mehr Unterschiede zwischen struct und class gibt als die Sichtbarkeit. So unter dem Motto, bei class liegen eben die Member nicht hintereinander im Speicher wie bei struct.

    Dem ist aber nicht so. IBV at lediglich nicht "bei Structs und Klassen" gesagt, weil fuer den C++-Programmierer beides sowieso das gleiche ist.

    Was ist mit den Verwaltungsbytes, so wie sie hier genannt wurden, wo leben die? Ich will doch bloß klipp und klar wissen wo alles liegt, wenn ich ein Objekt anlege.

    Dann frag doch danach, anstatt, wo der vector in deinem struct liegt 🙂 .

    Der C++-Standard kennt 3 verschieden Speicherklassen (wenn wir mal so Zeug wie register ignorieren): automatisch, statisch, dynamisch. Wie das genau von der Implementierung umgesetzt wird, bleibt dieser ueberlassen. Normalerweise (muss aber nicht so sein!) werden statische Variablen im Datensegment des Programms landen, automatische Variablen auf einem Stack (dem Stack, wenn man so will), dynamische Objekte im Freispeicher (dem Heap).
    Statische Objekte sind logischerweise alles , was mit static definiert wurde, aber auch globale Variablen.
    Dynamisch ist alles, was man mit new oder malloc & Konsorten erzeugt. Wobei nicht unbedingt gesagt ist, dass new und malloc den gleichen Heap benutzen. Das ist einer(!) der Gruende, nicht new und malloc zu mischen.
    Automatische Objekte sind alles andere, dies ist der Normalfall, den man immer waehlen sollte, wenn man keine guten Gruende dagegen hat. Die heissen automatisch, weil sie eben automatisch verwaltet werden, eine Eigenschaft, die man verliert, wenn man dynamischen Speicher nutzt. Deshalb packt man den Handler fuer dynamischen Speicher immer in ein automatisches Objekt, so dass man die Vorzuege automatischer Speicherverwaltung mit den Moeglichkeiten der dynamischen Speicherverwaltung* in einem einzigen Objekt hat. Genau das macht der vector.

    Was ist ein vector?

    Eine ganz naive Implementierung (nur die Member, nicht die Methoden) saehe so aus:

    template<typename T> class vector
    {
      T *data;
      size_t num_elements;
    };
    

    (der echte vector hat in der Regel 3 Pointer als Member, sonst nichts)
    Wenn der vector nun Speicher braucht, dann holt er sich den mit new (oder beim echten vector mit dem Allokator (das zweite Templateargument, das man meistens gar nicht wahr nimmt, dass es da ist), der aber per default new ist, wenn man nichts anderes angibt). Das heisst, das, was der vector speichert, liegt dann schon auf dem Heap. Aber wo der vector selbst liegt (also das Objekt, das in diesem Beispiel aus dem Pointer und dem size_t besteht), kann liegen wo man will. Dieses Objekt kann man, wie oben erklaert, in das Datensegment, den Heap oder den Stack legen, man hat die Wahl. Wobei der Heap ziemlich wenig Sinn macht, ausser man benoetigt eine dynamische Menge von vectoren. Dieser Teil ist das Vectorobjekt selbst, jetzt sollten auch die Antworten von oben verstaendlicher sein. Dass das Objekt intern noch Zeiger haelt, die eventuell irgendwo auf den Heap zeigen, ist nicht weiter von Belang. Der vector ist ja eine abgeschlossene Einheit, was der im inneren macht, interessiert nicht. Daher auch die folgende Relativierung: Ein vector muss nicht so funktionieren. Es waere zum Beispiel gut vorstellbar, dass der vector zuerst einmal versucht, seinen Inhalt in sich selber, also an der Stelle, die eigentlich fuer die Verwaltungsdaten vorgesehen ist, zu speichern und erst, wenn er mehr Speicher braucht, holt er tatsaechlich dynamischen Speicher. So spart er sich fuer kleine Datenmengen die aufwaendige dynamische Speicherverwaltung.

    *: Der grosse Vorteil dynamischer Speicherverwaltung ist, dass man erst zur Laufzeit wissen braucht, wie viel Speicher man benoetigt. Bei automatischer Speicherverwaltung muss zur Compilezeit die Groesse und Anzahl aller Objekte feststehen. Ein weiterer, kleiner Unterschied ist, dass bei manchen Implementierungen der Stack recht begrenzt ist (wenige Megabyte fuer alles), wohingegen der Heap fast nur durch die Moeglichkeiten des Computers begrenzt ist.



  • Danke fuer die sehr ausfuehrliche Erklaerung. Der Begriff automatische Variabel war mir voellig fremd. Kann es sein, dass es sehr viel schlechte C++ Literatur, Tuts usw gibt? Beispiele zu C++ sind meist zudem auch voll von new und delete. Kein Wunder dass soviel schlechter C++-Code geschrieben wird.



  • HeapStacker schrieb:

    Kann es sein, dass es sehr viel schlechte C++ Literatur, Tuts usw gibt?

    Ja, vor allem wenn es im Internet und/oder auf Deutsch ist.



  • HeapStacker schrieb:

    Kann es sein, dass es sehr viel schlechte C++ Literatur, Tuts usw gibt? Beispiele zu C++ sind meist zudem auch voll von new und delete. Kein Wunder dass soviel schlechter C++-Code geschrieben wird.

    in der tat. c++ ist halt kein java.



  • SeppJ schrieb:

    HeapStacker schrieb:

    IBV schrieb:

    Ich wurde sagen auf dem Heap, da bei structs die Member hintereinander im Speicher gespeichert sind.

    Also ist diese Vermutung und diese Aussage richtig? Die Aussage impliziert doch, dass es noch mehr Unterschiede zwischen struct und class gibt als die Sichtbarkeit. So unter dem Motto, bei class liegen eben die Member nicht hintereinander im Speicher wie bei struct.

    Dem ist aber nicht so. IBV at lediglich nicht "bei Structs und Klassen" gesagt, weil fuer den C++-Programmierer beides sowieso das gleiche ist.

    Was ist mit den Verwaltungsbytes, so wie sie hier genannt wurden, wo leben die? Ich will doch bloß klipp und klar wissen wo alles liegt, wenn ich ein Objekt anlege.

    Dann frag doch danach, anstatt, wo der vector in deinem struct liegt 🙂 .

    Der C++-Standard kennt 3 verschieden Speicherklassen (wenn wir mal so Zeug wie register ignorieren): automatisch, statisch, dynamisch. Wie das genau von der Implementierung umgesetzt wird, bleibt dieser ueberlassen. Normalerweise (muss aber nicht so sein!) werden statische Variablen im Datensegment des Programms landen, automatische Variablen auf einem Stack (dem Stack, wenn man so will), dynamische Objekte im Freispeicher (dem Heap).
    Statische Objekte sind logischerweise alles , was mit static definiert wurde, aber auch globale Variablen.
    Dynamisch ist alles, was man mit new oder malloc & Konsorten erzeugt. Wobei nicht unbedingt gesagt ist, dass new und malloc den gleichen Heap benutzen. Das ist einer(!) der Gruende, nicht new und malloc zu mischen.
    Automatische Objekte sind alles andere, dies ist der Normalfall, den man immer waehlen sollte, wenn man keine guten Gruende dagegen hat. Die heissen automatisch, weil sie eben automatisch verwaltet werden, eine Eigenschaft, die man verliert, wenn man dynamischen Speicher nutzt. Deshalb packt man den Handler fuer dynamischen Speicher immer in ein automatisches Objekt, so dass man die Vorzuege automatischer Speicherverwaltung mit den Moeglichkeiten der dynamischen Speicherverwaltung* in einem einzigen Objekt hat. Genau das macht der vector.

    Was ist ein vector?

    Eine ganz naive Implementierung (nur die Member, nicht die Methoden) saehe so aus:

    template<typename T> class vector
    {
      T *data;
      size_t num_elements;
    };
    

    (der echte vector hat in der Regel 3 Pointer als Member, sonst nichts)
    Wenn der vector nun Speicher braucht, dann holt er sich den mit new (oder beim echten vector mit dem Allokator (das zweite Templateargument, das man meistens gar nicht wahr nimmt, dass es da ist), der aber per default new ist, wenn man nichts anderes angibt). Das heisst, das, was der vector speichert, liegt dann schon auf dem Heap. Aber wo der vector selbst liegt (also das Objekt, das in diesem Beispiel aus dem Pointer und dem size_t besteht), kann liegen wo man will. Dieses Objekt kann man, wie oben erklaert, in das Datensegment, den Heap oder den Stack legen, man hat die Wahl. Wobei der Heap ziemlich wenig Sinn macht, ausser man benoetigt eine dynamische Menge von vectoren. Dieser Teil ist das Vectorobjekt selbst, jetzt sollten auch die Antworten von oben verstaendlicher sein. Dass das Objekt intern noch Zeiger haelt, die eventuell irgendwo auf den Heap zeigen, ist nicht weiter von Belang. Der vector ist ja eine abgeschlossene Einheit, was der im inneren macht, interessiert nicht. Daher auch die folgende Relativierung: Ein vector muss nicht so funktionieren. Es waere zum Beispiel gut vorstellbar, dass der vector zuerst einmal versucht, seinen Inhalt in sich selber, also an der Stelle, die eigentlich fuer die Verwaltungsdaten vorgesehen ist, zu speichern und erst, wenn er mehr Speicher braucht, holt er tatsaechlich dynamischen Speicher. So spart er sich fuer kleine Datenmengen die aufwaendige dynamische Speicherverwaltung.

    *: Der grosse Vorteil dynamischer Speicherverwaltung ist, dass man erst zur Laufzeit wissen braucht, wie viel Speicher man benoetigt. Bei automatischer Speicherverwaltung muss zur Compilezeit die Groesse und Anzahl aller Objekte feststehen. Ein weiterer, kleiner Unterschied ist, dass bei manchen Implementierungen der Stack recht begrenzt ist (wenige Megabyte fuer alles), wohingegen der Heap fast nur durch die Moeglichkeiten des Computers begrenzt ist.

    Schonmal nen Buch geschrieben?


  • Mod

    Ne, dafür hat er doch offensichtlich keine Zeit oder Lust



  • Arcoth schrieb:

    Ne, dafür hat er doch offensichtlich keine Zeit oder Lust

    würde sich aber mal voll lohnen. Ich find das ist mit eine der klarsten Kurzerklärungen die man so findet



  • Das finde ich aber auch. Ein Artikel hier im C++-Magazin wäre aber schon einmal ein guter Anfang. Gerade für mich als C++-Anfänger sind die Grundlagen sehr wichtig und wie und wo was im Speicher passiert gehört, wenn auch nur kurz angeschnitten, in jedes C++-Lehrwerk.



  • Toll erklärt, SeppJ.
    Noch ein paar Absätze für die Lesbarkeit einfügen und es wäre dann der Hammer.


Anmelden zum Antworten