std::vector push_back crash im Zusammenhang mit realloc



  • Hallo Forum,

    dieser code crasht in ptr[ 0 ].push_back( 0.0f ). Allerdings nur im Release mode!

    typedef std::vector< float > V;
    
    V s;
    
    V* ptr = NULL;
    
    // 1st "push_back" on ptr
    
    if ( V* tmp = (V*)realloc( ptr, sizeof( V ) ) )
    {
        ptr = tmp;
    
        new ( ptr ) V( s );
    }
    
    // 2nd "push_back" on ptr
    
    if ( V* tmp = (V*)realloc( ptr, sizeof( V ) * 2 ) )
    {
        ptr = tmp;
    
        new ( ptr + 1 ) V( s );
    }
    
    ptr[ 0 ].push_back( 0.0f );
    

    Ich hab mich schon dran tot debuggt... das zweite realloc scheint das
    Problem zu sein. Hab mir also im VS 2008 memory viewer angesehen, ob
    das realloc auch wirklich den alten memory block in den neuen kopiert
    und ja das tut es. Verstehe also nicht, wieso es einen crash gibt
    wenn ich auf das erste Feld im neu allokierten memory block zugreife?

    Hat jemand eine Idee?

    LG


  • Mod

    vector ist nicht trivial kopierbar, also kannst du nicht memcpy und Konsorten (realloc gehört auch dazu) dafür verwenden.


  • Mod

    edit: Hier stand Mist.



  • typedef std::vector< float > V;
    
    V s;
    
    std::vector<V> p;
    
    p.push_back( s );
    p.push_back( s );
    
    p[ 0 ].push_back( 0.0f );
    

    Ungetestet, aber so ähnlich sollte es gehen



  • Ich finde die Kombination seltsam. Wie kommt man auf die Idee, wo std::vector doch bekannt ist, mehrere Vektoren wieder so frickelig mit realloc anzulegen? Warum nicht

    vector<vector<float> > vv;
    

    ?!



  • V* ptr = NULL; 
    if ( V* tmp = (V*)realloc( ptr, sizeof( V ) ) )
    

    Was soll das denn? Also:
    1.) mit ptr == 0 ist dein realloc das gleiche wie malloc
    2.) bei C++ benutzt man new
    3.) Speicherallokation von C++ nicht mit der von C wie malloc,realloc oder calloc mischen


  • Mod

    knivil schrieb:

    1.) mit ptr == 0 ist dein realloc das gleiche wie malloc

    Und mit size==0 ist es wie free... Es ist nicht ganz sinnlos, malloc/free nicht mit realloc zu vermischen. I.d.R. wird man in C++ allerdings keins von beiden verwenden wollen.



  • Also der code so wie er da steht wird nicht eingesetzt.
    Das ist nur ein minimalistisches Beispiel hier für das Forum.

    Es geht nur darum herauszufinden, wieso es crasht.



  • camper schrieb:

    vector ist nicht trivial kopierbar, also kannst du nicht memcpy und Konsorten (realloc gehört auch dazu) dafür verwenden.

    Warum nicht? std::vector enthält doch eigentlich nur...

    pointer _Myfirst;
    pointer _Mylast;
    pointer _Myend;

    ...und sollte daher doch auch unproblematisch sein, wenn er während
    eines reallocs kopiert wird?



  • Non-PODs vertragen sich mit dem ganzen C-Speichergefrickel nicht, das ergibt undefiniertes Verhalten. Da gibts auch keine Veranlassung zu, sowas in C++ zu benutzen. Ganz unabhängig davon, ob das bei diesem einen Fall jetzt aus Versehen auf den ersten Blick eigentlich doch irgendwie funktionieren sollte - gewöhn dir sowas garnicht erst an.



  • Gast777 schrieb:

    Es geht nur darum herauszufinden, wieso es crasht.

    Weil das Kopieren von nicht-POD-Typen mit memcpy und Konsorten schlicht und ergreifend undefiniert ist. Da nützt es nichts, zu diskutieren, warum denn oder dass es ja eigentlich egal sein sollte, es ist so. Sowas macht man nicht. Punkt. 🙂



  • Gast777 schrieb:

    camper schrieb:

    vector ist nicht trivial kopierbar

    Warum nicht? std::vector enthält doch eigentlich nur...

    TriviallyCopyable



  • Also das man non-PODs auf diese Weise nicht kopieren sollte ist mir bewusst.

    Mich interessiert trotzdem, was genau in diesem hier genannten Fall auf Speicherebene passiert bzw. schief läuft. Das ist auch der Grund,
    warum ich so ein absolut minimalistisches Beispiel gepostet habe.

    Ich hatte die Hoffung, dass jemand genau erklären kann, wieso das reine
    Kopieren hier in diesem Fall nicht ausreicht. Warum genau crasht es,
    was fehlt oder wurde nicht korrekt initialisiert oder zeigt auf irgendwas
    ungültiges?


  • Mod

    Dann nimm dir einen Debugger und vollzieh das Programm Schritt für Schritt nach. Guck dir genau die Interna deiner vectoren an, wie sich diese verändern, ob der Speicher auf den sie zeigen noch gut ist und wann es genau kracht. Bei mir stürzt es beispielsweise nicht ab, aber ich habe vermutlich ein anderes System als du. Ist eben undefiniertes Verhalten. Ganz clevere Compiler optimieren nämlich einfach alles weg.

    Ein mögliches Absturzszenario welches ich mir vorstellen könnte, wäre ein vector mit Optimierung für kleine Felder, der einen Teil seiner internen Verwaltungsdaten als Speicher benutzt und den Heap erst dann anpackt, wenn die Datenmenge zu groß wird. Hier wurde dann der Zeiger auf die Daten nach dem realloc auf die eventuell schon freigegebenen alten Daten zeigen.



  • Ja ich hab mir schon alles reingezogen (disassembly und memory viewer),
    aber leider nichts rausfinden können. Das hat mich jetzt so genervt,
    dass ich hier einfach mal gepostet habe.

    Danke schon mal für die Vermutungen!



  • Es kann beispielsweise das Alignment nicht stimmen.


  • Mod

    knivil schrieb:

    Es kann beispielsweise das Alignment nicht stimmen.

    Das kann nicht passieren.



  • So wie ich das sehe, müssten die drei Pointer immer noch auf den gleichen Speicherbereich zeigen. Es kann sich also nur die Bedeutung geändert haben. Zum Beispiel könnte _Myfirst immer auf das zeigen, worauf data() zeigen sollte, wenn der Vektor leer ist, also auf den Speicherbereich direkt nach dem Vektor. Wenn du ihn reallokierst stimmt das nicht mehr und es kracht wenn du auf den Vektor zugreifen willst.

    Um das herauszufinden, musst du dir die Implementation vom Vektor im MSVC genau anschauen.


Anmelden zum Antworten