Importer:Error:WasEmpty



  • Nathan schrieb:

    Der Code ist UB.
    Das funktioniert nur, weil das Betriebssystem den Speicher noch nicht recycelt hat.

    Kann man es irgendwie merken, wann das OS den Speicher leert - vielleicht selbst anstoßen?



  • OK danke, alles klar 🙂

    #include <iostream>
    using namespace std;
    
    void dummy(){
        int *p_array = new int[10];
        for (int i = 0; i < 10; i++) {
            *p_array = i;
            p_array++;
        }   
        delete [] p_array;
    }
    
    int main(int argc, char** argv) {
    
        int *p_array = new int[10];                 // Zeiger auf ein Array im Heap
        int *p_merker = p_array;                    // p_merker simuliert die Übergabe (return)
    
        for (int i = 0; i < 10; i++) {
            *p_array = i;
            p_array++;
        }    
        p_array = p_merker;    
    
        delete [] p_merker;                         // Übergabe-Zeiger wird mit eckigen Klammern gelöscht
    
        for (int j = 0; j < 10; j++) {              // Array immer noch vollständig
            cout << j << ".:  " << *p_array << endl;
            p_array++;
        }
    
        cout << "---------------------" << endl;
    
        dummy();
    
        for (int j = 0; j < 10; j++) {              // Array immer noch vollständig
            cout << j << ".:  " << *p_array << endl;
            p_array++;
        }
    
        return 0;
    }
    


  • Cpp_Anfaeger schrieb:

    Nathan schrieb:

    Der Code ist UB.
    Das funktioniert nur, weil das Betriebssystem den Speicher noch nicht recycelt hat.

    Kann man es irgendwie merken, wann das OS den Speicher leert - vielleicht selbst anstoßen?

    Ja, mit delete. Damit gibst du Speicher an das OS zurück.
    Du darfst denn danach nicht mehr verwenden!
    Ob das OS den Speicher schon erneut verwendet, hängt damit zusammen wie viele andere Prozesse Speicher anfordern etc..
    Aber dir gehört er nicht mehr.
    Und du darfst dich auch nicht darauf verlassen, dass ein erneuter Call zu new denselben Speicher zurückgibt!



  • @Cpp_Anfaeger
    Zum Vermeiden solcher Fehler gibt es gute Hilfsmittel, wie z.B. die Debug-Heap Funktionen unter Windows.
    Mittels derer kann man es einrichten dass freigegebener Speicher mit einem bestimmten Muster gefüllt wird (üblicherweise 0xdddddddd ). Visual C++ aktiviert diese Funktionen per Default in Release-Builds Debug-Builds.

    Und wenn dein Programm in einer solchen Umgebung läuft, würdest du anhand der "komischen Zahlen" die von der 2. Ausgabeschleife ausgegeben werden merken dass etwas nicht so läuft wie es sollte.

    Auf Linux gibt es vermutlich ähnliche Funktionen/Tools. Bzw. auch Programme wie valgrind, die helfen können solche (und andere) Fehler zu finden.

    EDIT: Blödsinn korrigiert.



  • hustbaer schrieb:

    in Release-Builds.

    Bist du dir sicher dass das im Release so ist und nicht im Debug-Build?

    Ich kann mich auch irren, möchte nur dazulernen...



  • Nein, gar nicht. Ganz im Gegenteil.
    Ich bin mir sicher dass ich Blödsinn geschrieben habe. 😃

    Danke für den Hinweis!



  • Th69 schrieb:

    Dies ist unabhängig vom Datentyp - denn irgendwie muß die Freigabefunktion (delete[] bzw. free() bzw. betriebssystemabhängige Funktion) ja wissen, wieviel Speicher sie wieder freigeben muß (eine andere Alternative wäre, daß intern eine Mappingtabelle <Speicheradresse, Groesse> benutzt würde).

    Natürlich, die zugrunde liegende C/C++ runtime library muss wissen wieviel Speicher freigegeben wird. Normalerweise werden diese Informationen in dem Speicherbereich direkt vor dem zurückgelieferten pointer platziert. Man nennt das auch 'malloc overhead'.

    Das hat aber nichts mit dem Compiler zu tun. Der Compiler muss nur wissen aus wievielen Elementen das Array besteht, wenn er vor operator delete[] den Destructor jedes einzelnen Elementes aufrufen muss. In dem Fall reserviert der Compiler 4 Bytes extra (bei 32Bit) um die Anzahl Elemente zu speichern.

    - osdt



  • Cpp_Anfaeger schrieb:

    Ich denke, dass wir immer nich einen Speicherleck haben, trotz: delete [] zeiger

    Du traust der C/C++ runtime library nicht, oder?

    Wenn new[]/delete[] oder malloc()/free() nicht funktionieren würden, hätten wir nicht ein lauffähiges C/C++ Programm.

    Wenn Du genau wissen willst weshalb es doch funktioniert, schau dir mal den Quelltext einer open source C/C++ Bibliothek an. Man kann viel dabei lernen.

    - osdt



  • osdt schrieb:

    In dem Fall reserviert der Compiler 4 Bytes extra (bei 32Bit) um die Anzahl Elemente zu speichern.

    Du meinst, sowohl der Compiler als auch die Betriebssystemfunktion speichern je die Anzahl ab (insgesamt also zweimal)???



  • @Th69
    Nein.
    Der Heap* merkt sich was auch immer er benötigt um den Speicher wieder freigeben zu können.
    Das muss nicht die genaue Grösse des angeforderten Bereichs sein, und schon gar nicht die Anzahl der Elemente.
    (Und freigeben heisst hier nicht unbedingt ans System zurückgeben -- viele Heap Implementierungen geben Speicher grundsätzlich nie ans System zurück.)

    Es gibt Heaps die viele spezialisierte Free-Lists für Allokationen in einem bestimmten Bereich haben, z.B. 24-32 Byte.
    Die bekommen dann oft über die Adresse raus zu welcher Free-List die Allokation gehört -- müssen es also nicht irgendwo abspeichern. Die genaue Grösse die angefordert wurde lässt sich dabei aber nicht mehr rekonstruieren. Ist aber auch nicht erforderlich - der Bereich ist ja immer 32 Byte gross, auch wenn vielleicht nur 24 oder 28 angefordert wurden.

    Daher kann sich die C++ Runtime auch nicht auf sowas verlassen, und speichert selbst nochmal die Anzahl der Elemente ab. (Bzw. sie kann auch die Grösse in Bytes abspeichern und dann beim Freigeben durch sizeof(T) dividieren -- macht aber mMn. wenig Sinn, ich würde die Anzahl abspeichern.)

    *:
    Wobei "der Heap" nicht "das OS" sein muss. Das OS teilt Speicher oft nur mit Page-Granularität aus.



  • Danke für die Hinweise ... ja, das Heap Walking u. die Open Source Quellcodes werde ich mir anschauen.


Anmelden zum Antworten