Stack overlflow bei Benutzung vector



  • arr[200000];

    Meinste nicht, das hier das Problem liegt? Zweihunderttausend doubles liegen defintiv auf dem Stack, und nicht im Heap. So, dann machst du sowas:

    d->liste.push_back(a);

    Macht 400.000 doubles auf dem Stack in dem Moment. Oder doch 800.000 durch den Copykonstruktor?

    Jedenfalls mind. 400.000 doubles auf dem Stack.

    Wenn du das Problem umgehen willst, kannst du mal boost::array ausprobieren (ist auch im TR1 drin). Eine Art Vector, mit undynamischer Größe. 😉



  • @Artchi:

    wird nicht bei vector.push_back nur eine Referenz übergeben ? Warum sollte dann irgendwas was vorher im Heap gelegen hat aufeinmal zum kopieren aufm Stack liegen ?


  • Mod

    Greenhorn2006 schrieb:

    @Artchi:

    wird nicht bei vector.push_back nur eine Referenz übergeben ? Warum sollte dann irgendwas was vorher im Heap gelegen hat aufeinmal zum kopieren aufm Stack liegen ?

    refernz ist korrekt. in diesem falle also keine kopie. wie kopmmst du aber darauf, dass das original zuvor nicht auf dem stack war?



  • naja wenn es vorher auf dem Stack gewesen wäre, dann hätte das hier auch schon einen Stack overflow auslösen müssen:

    C* c = new C();

    Hier wird doch genauso schon in C ein Objekt vom Typ A angelegt - und da es sehr groß ist müsste das sofort nen Stack overflow geben wenns aufm Stack erzeugt wurde (als "m" meine ich) - gibt es aber nicht. Desweiteren habe ich mir mal die Pointer ausgeben lassen und "m" aus C sieht für mich wie eine Heap-Adresse aus.



  • ? Warum sollte dann irgendwas was vorher im Heap gelegen hat aufeinmal zum kopieren aufm Stack liegen ?

    Weil du vector<A> und nicht vector<A*> definiert hast?

    Also ich hab mir jetzt nicht den Standard angeschaut, aber soweit ich weiß bzw. in den Komitee-Diskussionen mitbekommen habe, ist bei den std-Containern sehr wohl das Problem, das mehrere Kopien erzeugt werden. Insgesamt drei inkl. dem Original-Objekt! Denn genau das will man im nächsten ISO-Standard ändern, weil zuviel Overhead alleine durch ein push_back() entsteht.

    Der push_back(T&) ist zwar by-Reference, aber trotzdem wird beim Ablegen in den Container eine Kopie erzeugt. Das kannst du nicht verhindern, außer du machst einen Container der Pointer hält.

    Ich habe auch mal einen Performance-Test mit mehreren Millionen Strings gemacht:

    std::vectorstd::string war ca. 4x so langsam wie ein std::vectorstd::string*. Kann nur daher kommen, das Kopien ohne Ende bei push_back() entstehen.

    C* c = new C(); ist übrigens bei 200.000 doubles als Attribut nicht unbedingt gefährlich für den Stack, das verträgt er sicherlich noch. Kann man aber z.B. beim VC++ einstellen, wie groß der Stack sein soll, ist also nicht immer sicher, wann es knallen muß.



  • Bei "new C()" liegt das member-array doch nicht aufm stack sondern aufm heap -> kein problem



  • @dragon: Es ging nicht um die Klasse C sondern um die Klasse A die in C enthalten ist 😉

    Aber so wie ichs jetzt verstanden habe, wird auch das aufm Heap erstellt und der Stack overflow kommt nur zustande, weil vector.push_back so viele Kopieroperationen macht.


  • Administrator

    Nochmals zusammenfassen:

    camper schrieb:

    lokale variablen und funktionsparameter (und temporäre objekte) werden immer auf dem stack angelegt

    Das sind eben alle die man einfach so hinschreibt

    BlablaFunktion(int XYZ)
    {
        char ch[255];
        double bg;
        CKlasseirgendwas K;
        std::string str;
    }
    

    XYZ, ch, bg, K, str sind alle auf dem Stack und werden sobald die Funktion vorrüber ist, wieder gelöscht, bzw. der Speicher wird automatisch freigegeben.

    Nun kann man gerade eben bei grösseren Objeckten, diese auf den Heap setzen. Dies sieht dann so aus:

    BlaBlaFunktion(int XYZ)
    {
        int* pInteger = new int;
        CKlasseirgendwas* pK = new CKlasseirgendwas();
        double bg;
    }
    

    XYZ und bg sind immer noch auf dem Stack und werden nach dem Funktionsaufruf gelöscht. pInteger und pK sind allerdings Zeiger auf Objekte, welche auf dem Heap liegen. Mit new kann man nämlich Speicher auf dem Heap für die jeweilen Objekte speichern und erhält einen Zeiger auf diesen Speicher zurück. Dieser Speicher wird auch nicht automatisch gelöscht, sondern wird beibehalten, bis man ihn selber wieder löscht, was man auf jeden Fall machen soll, sonst gibt es Speicherlecks. Also die Adresse zum Speicher unbedingt aufbewahren und sobald das Objekt nicht mehr gebraucht wird:

    delete pInteger, pK;
    

    So ist auch dieser Speicher wieder freigegeben.

    Ich würde dir drigend anraten ein Tutorial in C++ zu machen. Das sind schliesslich mehr als die Grundlagen. Wenn man davon nichts weiss, dann ist das nicht gut und man sollte sich da Wissen aneignen. Und in Bücher ist das meistens gut beschrieben und auch korrekt, während man im Forum hier manchmal nicht immer so sicher ist, können einem ja auch immer wieder Flüchtigkeitsfehler unterlaufen.

    Grüssli


  • Mod

    nochmal einzeln und geordnet:

    void D::fill() {
    	for (int i =0; i<10; i++){
    		A a;                 // lokale variable -> stack overflow
    		a.i = i;
    		liste.push_back(a);
    	}
    }
    
    C* c = new C();
    

    harmlos

    Warum führt das Ausführen von Fill() jetzt trotzdem zu einem Stack overflow ?

    siehe oben

    D* d = new D();
    
    	A a;  // lokale variable -> stack overflow
    	d->liste.push_back(a);
    

    anzumerken wäre noch, dass das ganze nur entsprechend dem verhalten verbreiteter compiler folgt. letztlich macht der standard keine aussage darüber, wie wo bewusste lokale variablen, temporäre objekte und funktionsparameter angelegt werden.



  • @Dravere: Vielen Dank für deinen Beitrag.

    Mir war allerdings schon bewußt wie sich das mit dynamisch alloziiertem Speicher verhält usw. und das nicht erst seit gestern 🙂

    Was mir halt vorher eben nicht klar war, war eben das Speicherbild zB der Klasse C , bei C* c = new C();
    Aber das ist nun nach den ganzen Posts hier um einiges klarer geworden, warum es da doch einen Stack Overflow gab.

    mfg GreehHorn



  • @Dravere! Ehm, danke für deine Mini-Tutorial. Aber ich denke, die meisten hier aus dem Thread haben schon gewusst, das erst bei new der Heap ins Spiel kommt. 😉


Anmelden zum Antworten