delete [] p ?



  • CStoll schrieb:

    Die Verwaltung der Arraylänge kostet zusätzlichen Aufwand, den kann sich der Compiler sparen, wenn er "weiß", daß er mit Einzelobjekten hantiert.

    dein beispiel zeigt aber, wie gering der zusätzliche aufwand wäre - im vergleich zu dem gewinn an konsistenz und dem verschwinden einer bösen potenziellen fehlerquelle, wenn delete[] wegfiele.

    Badestrand schrieb:

    Weil der Compiler das an gewissen Stellen ja gar nicht wissen kann, ob der übergebene Zeiger auf ein Array zeigt oder auf ein einzelnes Objekt:

    wenn er über die größe des speicherbereichs buch führen kann, könnte er doch genauso gut auch über die objektanzahl buch führen?



  • [][][] schrieb:

    wenn er über die größe des speicherbereichs buch führen kann, könnte er doch genauso gut auch über die objektanzahl buch führen?

    Der, der über die Größe des Speichers Buch führt, ist aber möglicherweise (bzw. meistens) jemand anderes, als derjenige, der sich um die Destruktion kümmert. Wenn z.B. die Operatoren new und delete auf malloc und free zurückgreifen, ist ihnen die Größe des Speichers egal, darum kümmern sich malloc/free. Die Destruktion von Objekten muss der C++-Teil übernehmen, dafür ist aber nur die Anzahl erforderlich. (Wenngleich man natürlich zwischen Anzahl und Größe umrechnen kann).



  • [][][] schrieb:

    CStoll schrieb:

    Die Verwaltung der Arraylänge kostet zusätzlichen Aufwand, den kann sich der Compiler sparen, wenn er "weiß", daß er mit Einzelobjekten hantiert.

    dein beispiel zeigt aber, wie gering der zusätzliche aufwand wäre - im vergleich zu dem gewinn an konsistenz und dem verschwinden einer bösen potenziellen fehlerquelle, wenn delete[] wegfiele.

    Es gibt verschiedene Möglichkeiten, die Größe des Arrays zu verwalten (u.a. auch über eine map<void*,size_t> oder per Zugriff auf die Verwaltungsdaten von malloc/free) - die jeweils ihre eigenen Vor- und Nachteile haben. Auf jeden Fall muß new[] diese Anzahl irgendwo hinterlegen und das kostet Platz* (und Rechenzeit).

    * Bei kleinen Objekten kann es durchaus vorkommen, daß du damit deinen speicherbedarf verdoppelst.



  • LordJaxom schrieb:

    Der, der über die Größe des Speichers Buch führt, ist aber möglicherweise (bzw. meistens) jemand anderes, als derjenige, der sich um die Destruktion kümmert. Wenn z.B. die Operatoren new und delete auf malloc und free zurückgreifen, ist ihnen die Größe des Speichers egal, darum kümmern sich malloc/free. Die Destruktion von Objekten muss der C++-Teil übernehmen, dafür ist aber nur die Anzahl erforderlich. (Wenngleich man natürlich zwischen Anzahl und Größe umrechnen kann).

    das überzeugt mich nicht. delete kennt die größe des speicherbereichs. delete[] kennt außerdem die anzahl der zu zerstörenden objekte. das heißt, dass beide informationen irgendwo abgelegt sein müssen, und der zugrunde liegende code weiß, wie er an diese informationen heran kommt.
    wenn er diese zwei size_t-variablen mit jedem new[] ablegen kann, warum dann nicht noch ein zusätzliches bit, um automatisch zwischen new und new[] zu unterscheiden?

    mal ne andere frage: wenn ich mein eigenes delete schreiben würde, könnte ich es theoretisch so schreiben, dass es ein notwendiges delete[] selbst erkennen und durchführen kann?



  • new/delete braucht die Information nicht, wieviele Elemente das Array nun hat (es ist immer genau 1), also wozu sollte es diese Information noch speichern? Das kostet nur Speicherplatz und Rechenzeit.

    PS: Wie du deine eigenen new/delete's implementierst, ist natürlich dir selber überlassen - der ANSI-Standard legt nur fest, daß es undefiniert ist, wenn du Array- und Single-Operatoren mischst.



  • CStoll schrieb:

    new/delete braucht die Information nicht, wieviele Elemente das Array nun hat (es ist immer genau 1), also wozu sollte es diese Information noch speichern? Das kostet nur Speicherplatz und Rechenzeit.

    es sollte diese information speichern, weil eine unterscheidung zwischen delete und delete[] fehleranfällig ist und weil es die syntax komplizierter als notwendig macht.

    die erhöhte rechenzeit zur abfrage eines bits halte ich für kaum relevant, wenn man den üblichen aufwand für eine (de-)allokation in relation dazu setzt.
    der speicherbedarf stiege in der tat an, günstigenfalls aber nur um ein bit (nicht gesetzt = nur ein element), das sich auf vielen plattformen bestimmt noch in den ohnehin vorhandenen verwaltungsinformationen unterbringen ließe.

    und für sehr kleine allokationen könnte man ja immer noch in eigener verantwortung auf malloc und free zurückgreifen.

    gibt es wirklich keine besseren gründe für eine unterscheidung außer den genannten?

    CStoll schrieb:

    der ANSI-Standard legt nur fest, daß es undefiniert ist, wenn du Array- und Single-Operatoren mischst.

    die frage war: ist es praktisch möglich, delete so zu implementieren, dass es ein notwendiges delete[] selbst erkennt und ausführt? es also egal ist, ob man delete oder delete[] aufruft?



  • [][][] schrieb:

    CStoll schrieb:

    new/delete braucht die Information nicht, wieviele Elemente das Array nun hat (es ist immer genau 1), also wozu sollte es diese Information noch speichern? Das kostet nur Speicherplatz und Rechenzeit.

    es sollte diese information speichern, weil eine unterscheidung zwischen delete und delete[] fehleranfällig ist und weil es die syntax komplizierter als notwendig macht.

    die erhöhte rechenzeit zur abfrage eines bits halte ich für kaum relevant, wenn man den üblichen aufwand für eine (de-)allokation in relation dazu setzt.
    der speicherbedarf stiege in der tat an, günstigenfalls aber nur um ein bit (nicht gesetzt = nur ein element), das sich auf vielen plattformen bestimmt noch in den ohnehin vorhandenen verwaltungsinformationen unterbringen ließe.

    Ein einzelnes Bit kann nicht alleine untergebracht werden, also mußt du mindestens ein Byte für die Information "ich bin ein Array" veranschlagen - aus Padding-Gründen meist noch mehr. Und dieses mußt du so anlegen, daß es nicht mit irgendwelchen Nutz-Informationen kollidiert.

    und für sehr kleine allokationen könnte man ja immer noch in eigener verantwortung auf malloc und free zurückgreifen.

    Und auf die Vorteile von new/delete (automatische Ctor/Dtor-Aufurfe etc) verzichten? Nein danke.

    gibt es wirklich keine besseren gründe für eine unterscheidung außer den genannten?

    Wenn dir die genannten Gründe nicht gut genug sind, bist du selber Schuld 😉 Mir reichen sie.

    CStoll schrieb:

    der ANSI-Standard legt nur fest, daß es undefiniert ist, wenn du Array- und Single-Operatoren mischst.

    die frage war: ist es praktisch möglich, delete so zu implementieren, dass es ein notwendiges delete[] selbst erkennt und ausführt? es also egal ist, ob man delete oder delete[] aufruft?

    Man könnte die Aufrufe von der Single Operatoren auf die entsprechenden Array-Operatoren umbiegen, das löst zumindest die Speicherverteilung. Aber ob man das Verhalten von new/delete direkt beeinflussen kann, bin ich mir nicht sicher (delete ruft einen Dtor auf und übergibt anschließend den Speicher an op delete; delete[] ermittelt die Arraygröße, ruft n Dtoren auf und übergibt den Speicher an op delete[]).



  • CStoll schrieb:

    Ein einzelnes Bit kann nicht alleine untergebracht werden, also mußt du mindestens ein Byte für die Information "ich bin ein Array" veranschlagen - aus Padding-Gründen meist noch mehr. Und dieses mußt du so anlegen, daß es nicht mit irgendwelchen Nutz-Informationen kollidiert.

    praktisch wirst du auf den meisten plattformen für dieses eine bit den platz finden. gibt es überhaupt eine plattform, auf der ein new[std::numeric_limits<size_t>::max() >> 1] nicht fehlschlägt?e

    CStoll schrieb:

    und für sehr kleine allokationen könnte man ja immer noch in eigener verantwortung auf malloc und free zurückgreifen.

    Und auf die Vorteile von new/delete (automatische Ctor/Dtor-Aufurfe etc) verzichten? Nein danke.

    das ist doch praktisch überhaupt nicht relevant. wie oft legst du so kleine objekte mit new an, dass der entstehende overhead für die anzahl überhaupt ins gewicht fällt?

    Wenn dir die genannten Gründe nicht gut genug sind, bist du selber Schuld 😉 Mir reichen sie.

    vielleicht ist mir ist konsistenz und sicherer code wichtiger als dir.
    ich gebe allerdings zu, von den heutigen maßstäben bei speicherausbau und rechengeschwindigkeit verwöhnt zu sein. allerdings wird auf einem rechner der c64-klasse c++ (oder dynamische speicherallokation überhaupt) nicht sehr sinnvoll sein.



  • [][][] schrieb:

    CStoll schrieb:

    Ein einzelnes Bit kann nicht alleine untergebracht werden, also mußt du mindestens ein Byte für die Information "ich bin ein Array" veranschlagen - aus Padding-Gründen meist noch mehr. Und dieses mußt du so anlegen, daß es nicht mit irgendwelchen Nutz-Informationen kollidiert.

    praktisch wirst du auf den meisten plattformen für dieses eine bit den platz finden. gibt es überhaupt eine plattform, auf der ein new[std::numeric_limits<size_t>::max() >> 1] nicht fehlschlägt?e

    Und wo soll dieser Platz deiner Meinung nach sein? Im allokierten Objekt geht nicht (schließlich weißt du nicht, ob und welche Bereiche des Objekts ungenutzt sind), dahinter auch nicht (bei Arrays wärst du dann im nächsten Objekt), also bleibt nur davor - und da mußt du darauf achten, daß du die Adressen "richtig" im Speicher ausrichtest, sonst wird es wirlich langsam.

    das ist doch praktisch überhaupt nicht relevant. wie oft legst du so kleine objekte mit new an, dass der entstehende overhead für die anzahl überhaupt ins gewicht fällt?

    Zum Glück entscheidest nicht du, was relevant ist und was nicht. Das hängt immer von der Anwendung ab (und z.B. bei Listen oder Bäumen ist der Overhead schon erheblich, bei jedem Knoten noch die Anzahl 1 zu speichern).

    Wenn dir die genannten Gründe nicht gut genug sind, bist du selber Schuld 😉 Mir reichen sie.

    vielleicht ist mir ist konsistenz und sicherer code wichtiger als dir.

    Konsistenz erreichst du aber eher damit, daß du auf nackte Speicher-Verwaltung verzichtest - nimm lieber std::vector<> und Kollegen, die kapseln solche Probleme für dich 😉



  • CStoll schrieb:

    Und wo soll dieser Platz deiner Meinung nach sein?

    hab doch schon ein beispiel gebracht. im obersten bit der allokationsgröße wäre auf den meisten plattformen eine möglichkeit.

    Konsistenz erreichst du aber eher damit, daß du auf nackte Speicher-Verwaltung verzichtest - nimm lieber std::vector<> und Kollegen, die kapseln solche Probleme für dich 😉

    es geht aber nicht um die standardbibliothek sondern um delete[]. wenn ich ausschließlich delete[] benutzen würde (bescheuert aber legitim), wäre das konsistent.

    wenn ich einen smartpointer schreiben könnte, der ohne einschränkungen sowohl für einzelne objekte als auch für arrays funktionieren würde, dann wäre das konsistent. geht aber ned, weil ich blöderweise zwischen delete und delete[] unterscheiden muss.



  • [][] schrieb:

    CStoll schrieb:

    Und wo soll dieser Platz deiner Meinung nach sein?

    hab doch schon ein beispiel gebracht. im obersten bit der allokationsgröße wäre auf den meisten plattformen eine möglichkeit.

    Ja, jetzt brauchst du nur noch eine plattformübergreifende Möglichkeit, da ranzukommen 😉 (wo malloc/free sich die Größe des Blocks merken, ist nicht standardisiert)



  • [][][][][][], Du ignorierst geflissen die Kern-Philosophie von C++: „Don't pay for what you don't use.“ Ganz egal, wie gering das zusätzliche Overhead wäre, es ist inakzeptabel. Aus genau demselben Grund ist ja z.B. auch der Destruktor einer Klasse nicht standardmäßig virtuell, obwohl das viele Sachen erleichtern würde.



  • CStoll schrieb:

    Ja, jetzt brauchst du nur noch eine plattformübergreifende Möglichkeit, da ranzukommen 😉 (wo malloc/free sich die Größe des Blocks merken, ist nicht standardisiert)

    uff. ich mag mich hier echt nicht um jedes einzelne bit zanken. ich bin mir sicher, dass irgendein cleverer bursche schon einen mechanismus dafür gefunden hätte, die plattform für die verwaltung der objektanzahl zuständig zu machen und die damit die möglichkeit hätte, sie sehr effizient zu verwalten.

    und ich bin mir auch sicher, dass sich kein programmierer darüber beschwert hätte. und sich damit viele tausend stunden debugging hätten einsparen lassen.

    in anderen sprachen hat man deshalb so späße wie garbage collectors eingebaut, damit man sich ums freigeben nicht mehr explizit kümmern muss.



  • Ja, es gibt etwa ein halbes Dutzend mögliche Strategien, die Größe eines allokierten Speicherblocks zu speichern (grob geschätzt). Und in der Regel sind die new/delete eines Compilers auch darauf ausgerichtet, mit dessen Speicherverwaltung zurechtzukommen (wobei nicht einmal festgelegt ist, daß new intern auf malloc() aufbauen muß). Der Kernpunkt dieser Diskussion ist, daß jedes System hinter den Kulissen sein eigenes Süppchen kochen kann - und wenn du dich nicht auf eins festlegen willst, mußt du alle Möglichkeiten kennen.



  • Konrad Rudolph schrieb:

    [][][][][][], Du ignorierst geflissen die Kern-Philosophie von C++: „Don't pay for what you don't use.“

    stimmt. aber fehlersuche wegen falschem delete kostet auch etwas, wenn auch nicht rechenzeit oder speicherplatz. und den extracode, den man dann und wann wegen der unterscheidung schreiben muss, gibts auch nicht kostenlos.

    Ganz egal, wie gering das zusätzliche Overhead wäre, es ist inakzeptabel. Aus genau demselben Grund ist ja z.B. auch der Destruktor einer Klasse nicht standardmäßig virtuell, obwohl das viele Sachen erleichtern würde.

    ein unterschied ist: für virtuelle destruktoren musste kein neues keyword eingeführt werden (ich sehe delete[] mal als eigenes keyword). der kosten-/nutzenfaktor ist günstiger.



  • und sagt doch mal ehrlich: wenn ihr eine entsprechende programmiersprache entwerfen würdet, würdet ihr wirklich eine unterscheidung zwischen delete und delete[] vorsehen? vielleicht könnt ihr dabei mal versuchen zu vergessen, dass ihr "c++-geschädigt" seid.



  • [][][] schrieb:

    und sagt doch mal ehrlich: wenn ihr eine entsprechende programmiersprache entwerfen würdet, würdet ihr wirklich eine unterscheidung zwischen delete und delete[] vorsehen?

    Nein, natürlich nicht. Aber ich würde auch nicht auf C-Kompatibilität achten und aus diesem Grund überhaupt gar nicht erst diese dummen C-Array-Konstrukte erlauben.

    Wie es der Zufall so will arbeite ich tatsächlich am Design einer Programmiersprache, viele ähnliche Konzepte wie C++ verfolgt. C-ähnliche Arrays gibt es hier nicht. Es gibt lediglich rohen Speicher, auf dem man tun und lassen kann, was man will – ähnlich dem C++-Allokator-Konzept.



  • [][][] schrieb:

    und sagt doch mal ehrlich: wenn ihr eine entsprechende programmiersprache entwerfen würdet, würdet ihr wirklich eine unterscheidung zwischen delete und delete[] vorsehen?

    Ja, wuerde ich sofort, wenn ich auf die dumme Idee kaeme, in einer objektorientierten Sprache Arrays zu erlauben, die keine eigenen Objekte sind. Wie KR schon sagt, ist die ganze Problematik aus den Zugestaendnissen an das laestige C-Erbe entstanden.


Anmelden zum Antworten