delete [] statt delete?



  • hi
    wenn ich das tue:

    int *i=new int[10];
    delete i;
    

    habe ich einen speicherleak.

    was passiert aber wenn ich das mache?

    int *i=new int;
    delete [] i;
    

    eigendlich ist das ja gleichbedeutend mit

    int *i=new int[1];
    delete [] i;
    

    oder gibt es da noch unterschiede?



  • blubbb schrieb:

    hi
    wenn ich das tue:

    int *i=new int[10];
    delete i;
    

    habe ich einen speicherleak.

    Ist sogar schlimmer: Undefiniertes Verhalten

    blubbb schrieb:

    was passiert aber wenn ich das mache?

    int *i=new int;
    delete [] i;
    

    Genauso: Undefiniertes Verhalten

    blubbb schrieb:

    eigendlich ist das ja gleichbedeutend mit

    int *i=new int[1];
    delete [] i;
    

    Nein, ist es nicht. new int ist nicht dasselbe wie new int[1] . Hinten rum wird da möglicherweise "irgendetwas" anderes gemacht. Und deswegen muss auch das passende delete dazu. Was das "irgendwas" ist, ist da eigentlich total unwichtig, wenn es um die richtige Anwendung geht. Dazu sagt der C++ Standard auch nicht viel.

    kk



  • ok danke



  • Bei der Anweisung mit dem [] Operator wird zusätzlich zu deinem Objet/Objekten noch die Größe des Arrays gespeichert. Bei new int [1] wäre dies dann "größe|Objekt|Obj..|..." wobei bei new int nur "Objekt" im speicher abgelegt wird. Dies ist zwar nicht so vorgeschrieben wird aber oft so vom Compiler gemacht.



  • Und wie wird das dann in C gelöst, da wird free für pointer-arrays und für pointers verwendet.
    😕



  • Bin beim Googeln hierüber gestolpert: http://www.daniweb.com/forums/thread7497.html



  • Ob nun in C oder C++ die Größe des allokierten Speichers wird wohl bei beiden im Hintergrund mitgespeichert werden. Irgendwo her muss das System ja wissen wie viel Speicher freigegeben werden muss. Es kann ja nicht einfach hingehen und raten.

    Edit: Die Größe kann auch als Zeiger auf das letzte allokierte Element verstanden werden. Oder auch andere Formen der Implementation durch den Compiler.



  • i3v schrieb:

    Und wie wird das dann in C gelöst, da wird free für pointer-arrays und für pointers verwendet.
    😕

    In C müssen aber bei einem free(...) auch keine Destruktoren ausgeführt werden.

    Prinzipiell sollten new[] und delete[] sowieso zugunsten der Standard-Container vermieden werden.



  • Prinzipiell sollen zudem new und delete den Smart Pointern weichen, die ab C++0x Einzug in die Standardbibliothek erhalten.

    HighLigerBiMBam schrieb:

    Ob nun in C oder C++ die Größe des allokierten Speichers wird wohl bei beiden im Hintergrund mitgespeichert werden. Irgendwo her muss das System ja wissen wie viel Speicher freigegeben werden muss.

    Muss nicht unbedingt die Grösse sein. Es kann ja auch vor jedem Element ein Byte auf 0 gesetzt sein und am Schluss auf ~0 sein. Aber meistens ist es so gemacht wie du gesagt hast (mit Pointern).
    Was mich aber an dem Zitat nervt: es ist nicht das System. malloc() und free() sind keine Systemcalls. Jedes Programm kann new und delete bzw. new[] und delete[] global nach eigenen Wünschen definieren. Genau das disqualifiziert dich mit dieser Aussage:

    HighLigerBiMBam schrieb:

    Dies ist zwar nicht so vorgeschrieben wird aber oft so vom Compiler gemacht.

    Du weisst ja bereits, dass das mit der Implementation der Standardlib (beziehungsweise deiner eingebundenen Speicherverwaltungsbibliothek) zu tun hat und nichts mit dem Compiler.



  • Denkst du wirklich das die Speicherverwaltungsbibliothek vom Himmel gefallen ist? Auch diese wurde von einem Compiler erstellt. Ich habe extra das Wort Betriebssystem vermieden und System gesagt, weil ich das System meinte und nicht das Betriebssystem.



  • Foo* f=new foo[10];
    muß ja den Speicher anlegen, zum Beispiel mit malloc (faktisch wohl mit ::operator new) und dann auch noch 10 Konstruktoren ausführen. Soweit kein Problem.
    Nur könnte malloc so geschrieben sein (zum Beispiel als Buddy-Allocator), daß es zugunsten der Geschwindigkeit gleich Platz für 16 Foos macht statt nur für 10.
    Deswegen kann
    delete[] f;
    sich nicht auf die Größe des Speichers verlassen, den malloc geliefert hat und der vielleicht mit Tricks herasgefunden werden könnte.
    Ginge es nur ums Wegwerfen des Speichers, wäre es egal. Aber die 10 Destruktor-Aufrufe dürfen ja nicht 16 Destruktoraufrufe sein! Sonst würde man Destruktoren auf Speicher aufrufen, der gar nicht konstruiert wurde.
    Deswegen muß prinzipiell new[] sich irgendwo merken, wieviele Objekte es waren. Sinnigerweise zieht new[] einfach ein paar Bytes mehr und schreibt als ersten size_t im Speicherbereich die Größe rein und dahinter erst die Objekte.
    Und dann wirds fatal, wenn man new[]-Speicher nur mit delete löscht oder new-Speicher mit delete[].
    Kawumm!

    Also merken: Nicht mischen!

    Und dann kommt der Schlauberger-Compiler dran. Wir wollen ja keine Mehrkosten als in C oder asm haben für den selben Zweck.
    Wenn Foo (und dessen Basisklassen) einen leeren Destruktor haben, oder es gar um int geht, braucht man die Anzahl dann doch nicht.
    Dann macht new[] tatsächlich nichts anderes, als Speicher anzulegen und die Konstruktoren aufzurufen (falls vorhanden). Und vor allem macht delete[] nichts anderes als delete. Bei deinem int-Fall wird new[]/delete auf vielen Compilern zu keinem Fehler führen. Aber das ist nicht garantiert, wie schon gesagt, es klappt nur zufällig.

    Und dann kommt der Schlauberger-Compiler nochmal dran. In C++ werden oft VIELE kleine Objekte mit new angelegt, um die Vorteile der Laufzeitpolymorphie benutzen zu können. Das schreit nach einem small object allocator. Andererseits werden mit new[] fast immer nur größere Speicherbereiche angelegt, das quängelt dezent danach, daß new[] lieber ohne Umwege ein klassisches malloc benutzt. Deswegen könnte der Compilerbauer sogar new/delete und new[]/delete[] ganz trennen und verschiedene Speicherbereiche nehmen und ganz und gar verschiedene Implementierungen. (Hab ich aber noch nicht erlebt.)


Log in to reply