Stack und Heap bei Klassen



  • KasF schrieb:

    Die Frage ist auch eher die, wieso aufm Heap ? Sehe immer viele Codes, wo es HeapObjekte gibt, obwohl ein StackObjekt es auch tuen würde ...

    Ich wage mal folgende Behauptung: 9 von 10 "Programmierern" kennen ueberhaupt nicht den Unterschied zwischen Heap und Stack...



  • Amateur schrieb:

    Weil eine Klasse ja unter Umständen ziemlich groß werden kann

    Klassen sollte meiner Meinung nach nicht GROß sein. Klein, übersichtliche Schnittstellen und alles schön zusammenkapseln, was auch zusammen gehört.



  • KasF schrieb:

    Die Frage ist auch eher die, wieso aufm Heap ? Sehe immer viele Codes, wo es HeapObjekte gibt, obwohl ein StackObjekt es auch tuen würde ...

    Hi,

    ich denke, hier geht es nicht nur um "Heap vs. Stack", sondern mehr um "wird von alleine aufgeräumt" vs. "muss ich selbst deleten". Und da fällt eben "das integrierte int" unter die zweite Kategorie (wird automatisch mit dem foo zusammen abgeräumt) - und schließlich um "Ownership" (aggregiere ich nur einen A*, kann ich ihm ein A von außen zuweisen, das dem umschließenden Objekt eigentlich nicht "gehört")...

    Schließlich ist es dem Programmierer doch eigentlich ziemlich egal, in welchem Speicherbereich sein Objekt liegt (solange irgendjemand dafür sorgt, dass genug davon da ist). Viel wesentlicher sind doch die Design- und Handlings-Fragen....

    Gruß,

    Simon2.



  • Mhh ja ich weiß...
    Na gut: würdest du empfehlen, eine Klasse mit einem vector von 256 PALETTEENTRY Strukturen (jeweils 4 Byte groß) und einer LPDIRECTDRAWPALETTE Variable (ein Zeiger auf eine andere Klasse schätz ich) mit ein paar Methoden und so eher auf dem Stack oder auf dem Heap zu erzeugen. Wenn man bedenkt, dass man vielleicht nicht nur ein Objekt davon benötigt, sondern mehrere.
    Oder anders gefragt, ab wann sollte man sein Objekt auf dem Heap erzeugen und wann nicht...



  • Simon2 schrieb:

    ich denke, hier geht es nicht nur um "Heap vs. Stack", sondern mehr um "wird von alleine aufgeräumt" vs. "muss ich selbst deleten".

    Ja hast ja recht, bin irgendwie vom Weg abgekommen 🙂



  • Amateur schrieb:

    würdest du empfehlen, eine Klasse mit einem vector von 256 PALETTEENTRY Strukturen (jeweils 4 Byte groß)

    Wenn der vektor ein std::vector ist und sein Speicher ehe dynamisch besorgt, dann natürlich nicht.

    Amateur schrieb:

    Wenn man bedenkt, dass man vielleicht nicht nur ein Objekt davon benötigt, sondern mehrere.

    Wieviel sind mehrere ?

    Amateur schrieb:

    Oder anders gefragt, ab wann sollte man sein Objekt auf dem Heap erzeugen und wann nicht...

    Normalerweise kommt der Heap bei mir nur bei Polymorphie etc. ins Spiel, ansonsten nie. Falls ich aber so viele Objekte brauche die der Stack nicht aufnehmen kann, kommt doch der Heap ins Spiel.



  • KasF schrieb:

    ...Falls ich aber so viele Objekte brauche die der Stack nicht aufnehmen kann, kommt doch der Heap ins Spiel.

    Naja, das geht aber ja auch fast nur mit Arrays oder Rekursionen; statt Arrays verwende ich eigentlich eh fast immer Container (die das dann selbst auf den Heap legen) und Letzteres kenne ich eigentlich nur als "unneccessary cleverness" 😉
    Wenn jemand bei uns (weitlaufende) Rekursionen in produktiven Code einbaut, bekommt der sowieso schnell die Programmierpolizei auf den Hals. ....

    Gruß,

    Simon2.



  • Ja der Vektor ist ein std::vector. Wieviele Objekte benötigt werden hängt immer vom Einsatzgebiet der Klasse ab.
    Und man weiß ja auch nie wie groß der Stack auf dem PC wo das Programm läuft ist. Und da der Stack im Vergleich zum Heap eher klein ist (oder?) hab ich gedacht sollte man Objekte, die mehr Speicher brauchen eher auf den Heap packen.
    Wie sieht es denn mit lokalen Variablen von Memberfunktionen aus, wenn ich ein Objekt der Klasse auf dem Heap erzeuge. Die sollten dann ja auch auf dem Heap erzeugt werden oder?



  • Simon2 schrieb:

    Naja, das geht aber ja auch fast nur mit Arrays oder Rekursionen;

    Ich frag mich gerade wie man dynamisch auf dem Stack alloziert - ausser den Stackpointer direkt zu manipulieren :D.

    Grüsse

    *this



  • Simon2 schrieb:

    Naja, das geht aber ja auch fast nur mit Arrays

    Mein ich ja 🙂 War bissl ungenau ausgedrückt.

    Amateur schrieb:

    Die sollten dann ja auch auf dem Heap erzeugt werden oder?

    AFAIK nicht ...



  • Amateur schrieb:

    Ja aber wo ist dann der Unterschied, ob ich die Membervariable so erzeuge wie oben oder so:

    class foo
    {
    foo() {zahl = new int;}
    //...
    int * zahl;
    }
    

    unterschied zwischen heap und stack:
    der stack ist wie der name schon sagt ein stapelspeicher,
    nun, wozu nennt sich der wohl stapelspeicher...
    wenn ein programm ausgeführt wird, werden bei jedem funktionsaufruf (der erste wäre zb main) ein sogenanntes stackframe erzeugt (abhängig von der callingconvention die der compiler auserkoren hat für eine funktion).
    solche stackframes bestehen im prinzip aus den ganzen automatischen variablen

    class Foo { };
    
    void Bar()
    {
     Foo f2;
    } //stackframe von bar wird zerstört, destruktor von Foo wird aufgerufen
    
    int main(int, char **)
    {
     int x = 0; //liegt als erste variable am stackframe der funktion main
     Foo f; //ganze klasse wird konstruiert, liegt ebenfalls im stackframe von main
     Foo* pf = NULL; //pointer liegt am stack, das potentielle Foo objekt liegt irgendwo im speicher, womöglich auch am heap
    
    } //stackframe wird zerstört, destruktor von f wird ausgeführt, pf ist ja ein pointer und kein objekt daher entsteht hier ein memoryleak wenn pf auf ein objekt zeigt.
    

    wobei es gibt auch in manchen systemen die funktion void* _alloca(size_t) welche am stackframe der zurzeit ausgeführten funktion allokiiert.

    und jetzt heap 🙂
    malloc, der new operator, bzw selbstgeschriebene allokatoren sind meist auf platformspezifischen versionen aufgebaut, und die allokiieren im freien speicherbereich des prozesses.

    der unterschied, beim stack ist der programmverlauf der "memorymanager" wobei beim heap es der systemspezifische memorymanager ist (egal wie tief er vergraben sein kann in wrappercode)

    und jetzt aufs eigentliche problem:

    class foo
    {
    foo() {zahl = new int;}
    //...
    int * zahl;
    };
    
    class bar
    {
    bar() : zahl(0) {}
    //...
    int zahl;
    };
    
    int main(int, char**)
    {
     foo f; // f liegt am stackframe von main, f.zahl liegt auch am stack, aber f.*zahl liegt am heap 
     bar b; // b liegt am stackframe von main, b.zahl liegt auch am stack
     foo *pf; //pf liegt am stackframe von main, *pf liegt am heap, *pf.zahl liegt am  heap, *pf.*zahl liegt am heap
     bar *pb; //pb liegt am stackframe von main, *pb liegt am heap, *pb.zahl liegt am heap
    }
    

    hoffe diese kurze erklärung war ausführlich genug 🙂



  • Amateur schrieb:

    ...Wieviele Objekte benötigt werden hängt immer vom Einsatzgebiet der Klasse ab....

    Stimmt prinzipiell, aber sooo klein ist der Stack auch nicht. Mit dem Problem würde ich mich auseinandersetzen, wenn es wirklich auftritt (und selbst dann dürfte vermutlich das Setzen einer Compilervariablen sehr viel schneller sein als das Umstrukturieren seiner Anwendung). Die Gefahr von Speicherlecks durch falsches "Heaphandling" ist da sehr viel größer (leider gibt's in C++ ja immer Stack/Auto und Heap/Manuell gekoppelt).
    Selbst bei unserem größten Projekt war Speichermangel NIE ein Grund für eine "Heapisierung von Variablen"....
    Und "vorauseilenden Gehorsam" sehe ic da auch fehl am Platze.

    Ach ja: Leg mal ohne Arrays und Rekursionen wirklich viele Stackobjekte an, dann wirst Du vermutlich wissen, was ich meine. 😃

    Gruß,

    Simon2.



  • Gast++ schrieb:

    Simon2 schrieb:

    Naja, das geht aber ja auch fast nur mit Arrays oder Rekursionen;

    Ich frag mich gerade wie man dynamisch auf dem Stack alloziert - ausser den Stackpointer direkt zu manipulieren :D....

    wüsste ich auch nicht ... aber ich weiß auch nicht, wie Du diese Aussage in Zusammenhang mit meinem Post bringst.

    Gruß,

    Simon2.



  • Simon2 schrieb:

    Gast++ schrieb:

    Simon2 schrieb:

    Naja, das geht aber ja auch fast nur mit Arrays oder Rekursionen;

    Ich frag mich gerade wie man dynamisch auf dem Stack alloziert - ausser den Stackpointer direkt zu manipulieren :D....

    wüsste ich auch nicht ... aber ich weiß auch nicht, wie Du diese Aussage in Zusammenhang mit meinem Post bringst.

    Gruß,

    Simon2.

    unter windows

    void* _alloca(size_t)
    


  • Gast++ schrieb:

    Simon2 schrieb:

    Naja, das geht aber ja auch fast nur mit Arrays oder Rekursionen;

    Ich frag mich gerade wie man dynamisch auf dem Stack alloziert - ausser den Stackpointer direkt zu manipulieren :D.

    z.b. damit: http://www.mkssoftware.com/docs/man3/alloca.3.asp
    ist zwar nicht standard, der GCC z.b. hat das.
    🙂



  • KasF schrieb:

    Simon2 schrieb:

    Naja, das geht aber ja auch fast nur mit Arrays

    Mein ich ja 🙂 War bissl ungenau ausgedrückt.

    Amateur schrieb:

    Die sollten dann ja auch auf dem Heap erzeugt werden oder?

    AFAIK nicht ...

    Dann müsste sich ja der Stackpointer nach einem push_back() eines Stack-vectors verändern (irgendwo muss er mit dem Wert ja bleiben) ; tut er aber nicht!

    Grüsse

    *this



  • pale dog schrieb:

    Gast++ schrieb:

    Simon2 schrieb:

    Naja, das geht aber ja auch fast nur mit Arrays oder Rekursionen;

    Ich frag mich gerade wie man dynamisch auf dem Stack alloziert - ausser den Stackpointer direkt zu manipulieren :D.

    z.b. damit: http://www.mkssoftware.com/docs/man3/alloca.3.asp
    ist zwar nicht standard, der GCC z.b. hat das.
    🙂

    Und dann mit "placement new" draufgehen?
    Kitzel mich damit ich lachen kann... 😃

    Grüsse

    *this



  • Gast++ schrieb:

    pale dog schrieb:

    Gast++ schrieb:

    Simon2 schrieb:

    Naja, das geht aber ja auch fast nur mit Arrays oder Rekursionen;

    Ich frag mich gerade wie man dynamisch auf dem Stack alloziert - ausser den Stackpointer direkt zu manipulieren :D.

    z.b. damit: http://www.mkssoftware.com/docs/man3/alloca.3.asp
    ist zwar nicht standard, der GCC z.b. hat das.
    🙂

    Und dann mit "placement new" draufgehen?

    besser nicht, kann allein schon wegen unpassenden alignments schief gehen...
    🙂



  • pale dog schrieb:

    Gast++ schrieb:

    pale dog schrieb:

    Gast++ schrieb:

    Simon2 schrieb:

    Naja, das geht aber ja auch fast nur mit Arrays oder Rekursionen;

    Ich frag mich gerade wie man dynamisch auf dem Stack alloziert - ausser den Stackpointer direkt zu manipulieren :D.

    z.b. damit: http://www.mkssoftware.com/docs/man3/alloca.3.asp
    ist zwar nicht standard, der GCC z.b. hat das.
    🙂

    Und dann mit "placement new" draufgehen?

    besser nicht, kann allein schon wegen unpassenden alignments schief gehen...
    🙂

    🙂 Na isset denn die Möchlickeit...

    Denke das gehört noch in den Kontext unserer gestrigen Sammlung gekonnt exceptioneller (im wahrsten Sinne) Ausstiege aus lästigen main()-Routinen und ist sogar recht weitgehend "portabel"! 🙂

    Grüsse

    *this


Anmelden zum Antworten