delete[] (ptr+offset) ==> undefiniertes verhalten?



  • Ich habe mal aus Spaß dieses programm geschrieben. Zu Beginn habe ich mich gewundert, woher delete[] weiss, wieviele Bytes freigegeben werden müssen. Dann habe ich dies hier gefunden:

    Anmerkung: new[] merkt sich (genau wie malloc()) intern die Größe des reservierten Speichers. Es gibt jedoch keine portable Möglichkeit, auf diese Informationen zuzugreifen.

    Um das ganze etwas zu überstrapazieren, habe ich dieses Programm geschrieben. Offensichtlich wird das erste delete ignoriert.
    Kann mir jemand erklären, wie das intern funktioniert und ob es überhaupt möglich ist ein Array nur teilweise zu löschen?

    #include <iostream>
    
    using namespace std;
    
    //Kompillierbar mit minGW
    int main()
    {
        int a;
        char *ptr;
        cin >> a; //6 eingeben
        ptr = new char[a];
        cin >> ptr; //'12345' eingeben
        delete[] (ptr+3);
        cout << ptr << endl;  //'12345' wird ausgegeben
        delete[] ptr;
        cout << ptr << endl; //sinnloser Bytesalat wird ausgegeben
        return 0;
    }
    


  • deleteUser schrieb:

    Offensichtlich wird das erste delete ignoriert.

    Wird es nicht, es erzeugt nur undefiniertes verhalten. Kann also alles möglich passieren. Dass hinterher bei der Ausgabe noch die "12345" ausgegeben wird ist Glückssache.

    Kann mir jemand erklären, wie das intern funktioniert

    Pauschal nicht. Ist eben von Plattform zu Plattform unterschiedlich, manchmal sogar innerhalb der selben Plattform abhängig von der Größe des allokierten Speicherbrockens.

    und ob es überhaupt möglich ist ein Array nur teilweise zu löschen?

    Nein, nicht wirklich.


  • Mod

    deleteUser schrieb:

    Offensichtlich wird das erste delete ignoriert.

    Bei mir nicht. Undefiniertes Verhalten eben.

    ob es überhaupt möglich ist ein Array nur teilweise zu löschen?

    Nein.

    (Dir ist aber schon klar, dass alles was new[] kann, vector besser kann?)



  • Danke für die schnellen und präzisen Antworten! Ich habe demnächst vor eine Dll zu schreiben, in der ich sehr große Speichermengen anfordern muss. Deswegen wollte ich mich vorher informieren, wie ich dies am performantesten mache.
    Mir bleibt wohl nichts anderes übrig als:
    1. anfordern
    ==>vergrössern des bereichs
    2. neuen, grösseren Bereich anfordern
    3. Daten nach Bereich2 kopieren
    4. Bereich1 freigeben

    Das Ziel ist das Einlesen großer Datenmengen und das Verarbeiten davon. Bin ich da mit der Klasse vector wirklich besser beraten?



  • Sorry, habe mich schlecht ausgedrückt. Ist mir aber erst beim dritten Mal durchlesen aufgefallen:

    Die DLL soll sehr große binäre Daten einlesen und verarbeiten (Suchen, Ersetzen, Aufteilen, Ausgeben, etc...). Momentan wollte ich das einfach mit einem riesigen Array (dynamisch angefordert) machen. In den ersten 8 Bytes werden dann die Grösse des angeforderten Speichers und die Länge des benutzen Speichers festgehalten. Ich glaube kaum, dass die Klasse Vector dort wirklich angebracht ist, oder?


  • Mod

    Wie kommst du da drauf, dass du mit deinem Gefrickel irgendetwas besser machen könntest als std::vector? Hast du überhaupt Erfahrung mit vector? Die sollte man eigentlich haben, bevor man in C++ irgendwas ernsthaftes programmiert. Und eigentlich sogar bevor man new und Arrays kennenlernt. Wie hast du C++ gelernt?

    Wieso musst du die Datei überhaupt ganz einlesen? Klingt nach typischem Anfängerfehler.



  • Wie kommst du da drauf, dass du mit deinem Gefrickel irgendetwas besser machen könntest als std::vector?

    Das hier soll doch nicht meine Dll werden 😮
    Ich habe nur etwas rumprobiert und überlegt, wie delete[] und new[] überhaupt funktionieren (im Sinne von: Woher weiss das Programm, wieviel Speicherplatz freigegeben werden muss).

    Hast du überhaupt Erfahrung mit vector?

    Ja, ich habe Erfahrung mit std::vector. Ich habe std::vector bis jetzt immer als dynamisches Array, vor allem mit push_back() und pop_back() verwendet. Das ist in diesem Fall aber eigentlich nicht notwendig. Stellt sich jetzt die Frage, ob sich das für den Overhead wirklich lohnt. Ehrlich gesagt weiss ich nicht, um wieviel die Dll anschließend grösser wird. Ich habe eher Angst, dass die Funktionsaufrufe durch at() oder operator[] zuviel zeit kosten.
    ===> An sich spricht nichts gegen std::vector. (Eigentlich habe ich mir die Frage gerade selbst beantwortet xD)

    Wie hast du C++ gelernt?

    Mit einem Buch. Natürlich standen da nicht so welche beispiele drin, wie mein Programm. Es war ja eh nur so eine Frge a la "was wäre wenn". Hätte ja sein könne, dass man damit ein vorher angefordertes Array schnell und einfach kürzen kann.

    Wieso musst du die Datei überhaupt ganz einlesen?

    Das muss ich gar nicht. Es geht eigentlich überhaupt um das Verarbeiten von binären Daten. Das hört sich zwar verdammt blöd an, aber die Dll ist eigentlich nur für das Verarbeiten von binären Daten da. Ich will die Dll später in einer anderen Programmiersprache benutzen, um schneller und einfacher mit binären Daten umzugehen.


  • Mod

    deleteUser schrieb:

    Hast du überhaupt Erfahrung mit vector?

    Ja, ich habe Erfahrung mit std::vector. Ich habe std::vector bis jetzt immer als dynamisches Array, vor allem mit push_back() und pop_back() verwendet. Das ist in diesem Fall aber eigentlich nicht notwendig. Stellt sich jetzt die Frage, ob sich das für den Overhead wirklich lohnt.

    Welcher Overhead?

    Ehrlich gesagt weiss ich nicht, um wieviel die Dll anschließend grösser wird. Ich habe eher Angst, dass die Funktionsaufrufe durch at() oder operator[] zuviel zeit kosten.

    Optimierung anschalten? vector ist eine Abstraktion von dynamischen Arrays. Also von new[] und merken der Größe. Abstraktion kostet nichts. at ist natürlich langsamer als direkter Arrayzugriff, weil es mehr tut. operator[] ist reiner zugriff, das ist genau gleich schnell (sofern der Compiler optimiert).

    Wieso musst du die Datei überhaupt ganz einlesen?

    Das muss ich gar nicht.

    Warum machst du es dann? Deine Argumentation leuchtet mir nicht ein.



  • Optimierung anschalten? vector ist eine Abstraktion von dynamischen Arrays. Also von new[] und merken der Größe. Abstraktion kostet nichts. at ist natürlich langsamer als direkter Arrayzugriff, weil es mehr tut. operator[] ist reiner zugriff, das ist genau gleich schnell (sofern der Compiler optimiert).

    Ah danke. Ich dachte der operator[] wäre eine memberfunktion von std::vector und würde als Funktion behandelt werden. Dann sind Vectoren definitv bestimmt die bessere Wahl. Danke dir 👍


  • Mod

    deleteUser schrieb:

    Ah danke. Ich dachte der operator[] wäre eine memberfunktion von std::vector und würde als Funktion behandelt werden. Dann sind Vectoren definitv bestimmt die bessere Wahl. Danke dir 👍

    Es ist eine Memberfunktion. Aber das macht nichts. Compiler inlinen solche kleinen Funktionen automatisch (außer bei Debugbuilds), wenn der Code vorliegt. Was bei den STL-Containern der Fall ist. Wenn du jemals misst, dass vector langsamer ist als ein new-Array, dann hast du mit hoher Wahrscheinlichkeit irgendwelche Debugoptionen an*. Achtung: Bei manchen Standardbibliotheken (Microsoft) muss man die Debugfunktionalität explizit ausschalten, nicht einschalten.

    @alle: Ist letzteres eigentlich immer noch so? Früher kamen hier andauernd Leute an, die sich über vector beschwert haben und es waren am Ende die checked iterators des MSVC, die sie nicht abgeschaltet haben. Aber ich habe solche Threads schon lange nicht mehr gesehen.

    *: Ein wichtiger Vorteil von vector ist, dass man Debugfunktionen haben kann. Versuch mal bei new einen Bereichsfehler zu debuggen, das ist sehr viel mehr Aufwand.



  • SeppJ schrieb:

    Ist letzteres eigentlich immer noch so?

    Bis zur 2008er Version war das (unverständlicherweise) so.


Log in to reply