delete / free



  • Hallo,

    da ich C++ noch nicht so gut beherrsche, verstehe ich nicht ganz, wie ich einen Speicherbereich freigebe. Klar, "delete" (oder bei C halt "free") wären da ja die Stichwörter, aber wie kann ich denn angeben, wie viel vom Speicher freigegeben werden soll? Woher weiß diese Funktion, wie viel nicht mehr gebraucht wird?

    Mein Code funktioniert wie folgt:

    char *data;
    

    Irgend ein dynamisch geladener Programmcode allokiert dann Speicher, auf den ich mit data zeige. Die Größe dieses allkokierten Speichers bekomme ich in irgend einer Variable zurückgeliefert.
    Und wenn der Speicher nun nicht mehr benötigt wird, muss ich ihn ja irgendwie wieder freigeben! Aber wie mache ich das, wenn delete mir keine Möglichkeit lässt, eine Länge anzugeben und von alleine kann delete ja nicht wissen, wie viel gelöscht werden kann!

    Ich würde mich sehr freuen, wenn mich da jemand aufklären könnte! Besten dank!



  • Du brauchst nicht selbst eine Größe anzugeben. Wenn du mit new einen Speicherblock anforderst, wird genau dieser Block mit delete wieder freigegeben. Achte aber auf den Unterschied zwischen delete und delete[]!



  • Peter09 schrieb:

    Irgend ein dynamisch geladener Programmcode allokiert dann Speicher, auf den ich mit data zeige.

    Was heisst irgendein Code? Normalerweise hat man für jede Allokationsfunktion eine entsprechende Freigabefunktion. Diese solltest du auch nutzen, statt darauf zu spekulieren, dass der Speicherbereich auf eine bestimmte Weise angefordert wurde (z.B. durch new ).

    Du brauchst dir also zu überlegen, wie dein Speicher angefordert wird. Dann sollte sich auch herausstellen, wie du ihn freizugeben hast.



  • Okay...

    So sieht die Funktion aus, in der ich den Speicherbereich allokiere:

    char *get()
    {
    	std::string html;
    
    	// "html" füllen...
    
    	char *ret = new char(html.size());
    	memcpy(ret, html.c_str(), html.size());
    	return ret;
    }
    

    Ich glaube, da steckt irgendwie schon ein Fehler drin! Zuerst wollte ich einfach direkt html.c_str() als Rückgabewert nehmen, aber das kann ich ja schlecht, weil der Gültigkeitsbereich von "html" und damit auch von dem c_str-Speicherbereich ja nur in der get-Funktion ist.

    Wenn ich diesen Speicherbereich dann im Hauptprogramm mit "delete[] data;" wieder freigebe, bricht das Programm mit folgendem Fehler ab:

    *** glibc detected *** ./programm: free(): invalid next size (fast): 0x092fc8d0 ***
    

    Wenn ich den Speicher törichterweise einfach nicht freigebe, passiert etwas ganz seltsames: Am Ende, wenn das Programm aus der Funktion main zurückkehrt, bekomme ich vom System die folgende Meldung vorgeworfen:

    *** glibc detected *** ./programm: munmap_chunk(): invalid pointer: 0x088cd8e0 ***
    

    Sorry, aber das überfordert mich! Wird jemand daraus schlau und kann mir helfen? Vielen Dank!



  • Kannst du nicht einfach einen std::string zurückgeben statt dieser blöden Umkopiererei?



  • Sorry, das geht leider nicht 😞 Ich brauche da unbedingt was ganz elementares -> ein reiner Speicherblock mit den Daten.

    Der Grund ist, dass die Funktion "get" in einer shared library untergebracht ist und die endgültige Version der shared library dann später nicht unbedingt mit C++ erststellt wird. Und ein Pointer auf einen Speicherbereich ist so das elementarste, was ich mir vorstellen kann. Das sollte ziemlich flexibel sein!



  • Probiers bei dem new mal mit eckigen Klammern...



  • Das hier

    char *ret = new char(html.size());
    

    sollte eher so aussehen

    char *ret = new char[html.size() + 1];
    

    Dein new Aufruf erzeugt kein Array, sonder ein Zeiger au ein einzelnes char. Die +1 unten dient dazu, dass auch die abschließende 0 reinpasst.
    Du solltest besser strncpy statt memcpy nehmen.



  • Das ist mir jetzt peinlich...
    Die eckigen Klammern haben mir doch gleich geholfen, ich bedanke mich herzlich!

    Jetzt läuft der Code wunderbar!



  • Ich würde dir trotzdem von sowas abraten:

    char* str = get();
    delete[] str;
    

    Damit verlässt du dich auf eine bestimmte Implementierung und verlierst Flexibilität. Mach lieber eine entsprechende Freigabefunktion, z.B. release() (die Namen, besonders get , können aber viel besser gewählt werden). Falls du dann beim Aufräumen noch zusätzlich etwas tun willst oder nicht mehr mit delete[] löschst, kannst du das an einer Stelle im Code ändern, statt an hunderten.



  • Nexus schrieb:

    Ich würde dir trotzdem von sowas abraten:

    char* str = get();
    delete[] str;
    

    In so einem Fall sollte das Modul, das die get()-Funktion bereitstellt, auch eine dispose()-Funktion (oder anderer Name) liefern, die alles was mit get() geholt wurde entsorgt.

    Oder einfach std::string benutzen 🙂



  • Peter09 schrieb:

    Der Grund ist, dass die Funktion "get" in einer shared library untergebracht ist und die endgültige Version der shared library dann später nicht unbedingt mit C++ erststellt wird.

    Dann darfst Du weder new (oder dispose implementieren) nutzen, noch darf das extern "C" um die Funktion fehlen.



  • Mit malloc/free lässt sich auch sehr gut (mit PODs) arbeiten, auch wenn viele Puristen das hier anders sehen. 😉



  • ~john schrieb:

    Peter09 schrieb:

    Der Grund ist, dass die Funktion "get" in einer shared library untergebracht ist und die endgültige Version der shared library dann später nicht unbedingt mit C++ erststellt wird.

    Dann darfst Du weder new (oder dispose implementieren) nutzen, noch darf das extern "C" um die Funktion fehlen.

    Ich kann das nur noch einmal betonen: Du möchtest auf gar keinen Fall in einer Shared Lib einen Speicherbereich allokieren und außerhalb der Lib ihn mit delete o. ä. freigeben. Das gibt jede Menge Ärger und funktioniert meistens nicht (insbesondere, wenn deine Lib und dein späteres Programm mit unterschiedlichen Runtime-Libs gelinkt wurden).

    Grüße


Log in to reply