wie weiss delete[] array die Array Grösse



  • Hallo,

    Eine Frage zu dynamischen Arrays:

    int*array = new int[20];
    delete[] array;
    

    bracht delete[] array nicht die Informationen zur Größe von array um diese freigeben zu können?
    wenn ja, wo und wie ist die Größe verfügbar?
    sollte es dazu nicht eine Standardfunktion geben, memSizeInBytes(array) oder so?

    Vielen Dank im Voraus für jede hilfreiche Information!


  • Mod

    Wird sich irgendwo von der Speicherverwaltung gemerkt. Kommt man mit Standardmitteln nicht dran. Das kann zum Beispiel einfach in den Bytes vor dem Speicherbereich stehen, bei vielen Implementierungen aber auch ganz woanders.

    Statt new benutze vector oder ähnliches. Die merken sich ihre Größe und man kann zudem nichts mehr falsch machen bei der Speicherverwaltung.



  • ja, das ist ein fehler im design von C++.
    dem new sagt man die größe, also sollte man dem delete auch die größe sagen (müssen). das ist allerdings viel schlimmer, wenn man einmal sich um allocatoren selbst kümmern will/muss.
    das ist auch einer der gründe, warum man new und delete nicht manuell verwenden sollte, wenn man nicht gerade low-level arbeit macht.



  • dove schrieb:

    ja, das ist ein fehler im design von C++.
    dem new sagt man die größe, also sollte man dem delete auch die größe sagen (müssen).

    Soll das ein Scherz sein? Es hätte keinen Vorteil, beim Löschen eine Größe angeben zu müssen und wäre bloß eine weitere mögliche Fehlerursache (von denen es bei C++ schon mehr als genug gibt).



  • Andromeda schrieb:

    Soll das ein Scherz sein? Es hätte keinen Vorteil, beim Löschen eine Größe angeben zu müssen und wäre bloß eine weitere mögliche Fehlerursache (von denen es bei C++ schon mehr als genug gibt).

    Du müsstest die Größe ja nicht mit angeben, dass kann der compiler machen, den der kennt bei einem delete die Größe des Objekts. Mit der Information kann man einen allocator effektiver implementieren.



  • int elemente;
    cout<<"Wie viele Elemente moechten Sie anlegen?"<<endl;
    cin>>elemente;
    
    int array[]=new int[elemente];
    

    wo weiß der compiler das?



  • An der Stelle, wird er, bevor er die deallocation function aufruft, die Menge der Element da nachschlagen, wo er sie vorher abgelegt hat. Ok, dass ist an der Stelle jetzt nicht mehr der Compiler, sonder die Runtime. Worum geht es Dir bei Deiner Frage?



  • dove schrieb:

    ja, das ist ein fehler im design von C++.

    < C++14

    http://http://en.cppreference.com/w/cpp/memory/new/operator_delete

    void operator delete ( void* ptr, std::size_t sz ); (5) (since C++14)
    void operator delete[]( void* ptr, std::size_t sz ); (6) (since C++14)



  • Es ist mehr noch ein Fehler von C gewesen, wie Alexandrescu angemerkt hat:

    struct Blk {
        void* ptr;
        size_t size;
    }
    
    Blk malloc(int);
    void free(Blk);
    


  • ja, an alexandrescu habe ich auch gedacht. v.a. sein vortrag darüber, wie er (heutzutage) allokatoren designen würde. tja, und dann schaut man in die standard-pläne und findet so etwas wie polymorphic_allocator. zu wenig, zu langsam, zu umständlich...

    danke manni66 für den hinweis.



  • Torsten Robitzki schrieb:

    Du müsstest die Größe ja nicht mit angeben, dass kann der compiler machen, den der kennt bei einem delete die Größe des Objekts. Mit der Information kann man einen allocator effektiver implementieren.

    Wie wird das begründet? Was ist der Nachteil dabei, die Länge des allozierten Speicherblocks in ptr[-irgendwas] unterzubringen?



  • Andromeda schrieb:

    Torsten Robitzki schrieb:

    Du müsstest die Größe ja nicht mit angeben, dass kann der compiler machen, den der kennt bei einem delete die Größe des Objekts. Mit der Information kann man einen allocator effektiver implementieren.

    Wie wird das begründet? Was ist der Nachteil dabei, die Länge des allozierten Speicherblocks in ptr[-irgendwas] unterzubringen?

    Du must zur Laufzeit etwas ablegen, was in der Regel zur compiler-zeit bekannt ist. Und Du must etwas mehr Speicher aufwenden, als nötig ist, um die Information abzulegen.

    Meist sind Allokatoren so aufgebaut, dass sie für kleinere, Speichergrößen einen eigenen Allocator haben. Aus einem `delete t` könnte also bei zur compilezeit bekanntem sizeof(*t) das direkte Einhängen des Zeigers in eine freelist für diese Länge werden. Das wären dann zwei Zuweisungen.



  • Der genannte Vortrag ist dieser hier:
    https://www.youtube.com/watch?v=LIb3L4vKZ7U

    Ist zu empfehlen.



  • Torsten Robitzki schrieb:

    Andromeda schrieb:

    Torsten Robitzki schrieb:

    Du müsstest die Größe ja nicht mit angeben, dass kann der compiler machen, den der kennt bei einem delete die Größe des Objekts. Mit der Information kann man einen allocator effektiver implementieren.

    Wie wird das begründet? Was ist der Nachteil dabei, die Länge des allozierten Speicherblocks in ptr[-irgendwas] unterzubringen?

    Du must zur Laufzeit etwas ablegen, was in der Regel zur compiler-zeit bekannt ist. Und Du must etwas mehr Speicher aufwenden, als nötig ist, um die Information abzulegen.

    Okay, aber die Längeninformation zu sparen, halte ich für Mikrooptimierung. Meiner Meinung nach, ist das in den meisten Fällen total sinnfrei. Na ja, aber wer es braucht ...

    Torsten Robitzki schrieb:

    Meist sind Allokatoren so aufgebaut, dass sie für kleinere, Speichergrößen einen eigenen Allocator haben. Aus einem `delete t` könnte also bei zur compilezeit bekanntem sizeof(*t) das direkte Einhängen des Zeigers in eine freelist für diese Länge werden. Das wären dann zwei Zuweisungen.

    Ich sehe es schon kommen: irgendwann hat C++ auch einen schicken, standardmäßigen Garbage Collector. 🙂



  • Andromeda schrieb:

    Okay, aber die Längeninformation zu sparen, halte ich für Mikrooptimierung. Meiner Meinung nach, ist das in den meisten Fällen total sinnfrei. Na ja, aber wer es braucht ...

    Naja, wenn Du sehr viele kleine Objekte hast, deren dynamisch alloziierter Speicher nicht viel größer als sizeof(void*) ist, dann fällt das schon ins Gewicht. Entscheidend ist aber, dass wenn die Größe zur Compiler-Zeit bekannt ist, ich evtl. schon einige Schritte bei der Speicherverwaltung sparen kann. Und C++ ist halt um "You pay only for what you use..." (oder so ähnlich) gebaut 😉



  • Torsten Robitzki schrieb:

    Naja, wenn Du sehr viele kleine Objekte hast, deren dynamisch alloziierter Speicher nicht viel größer als sizeof(void*) ist, dann fällt das schon ins Gewicht.

    Ja, durchaus.

    Torsten Robitzki schrieb:

    Entscheidend ist aber, dass wenn die Größe zur Compiler-Zeit bekannt ist, ich evtl. schon einige Schritte bei der Speicherverwaltung sparen kann.

    Da kann ich dir jetzt nicht ganz folgen. Dass der Allokator die Größe nur intern kennt und man sie nicht abfragen kann, halte ich auch für eine Design Schwäche. Mit dem Vorschlag von Alexandrescu kann ich auch durchaus was anfangen. Da wird die Größe aber auch zur Laufzeit mitverwaltet. Aber wie willst du das einsparen und nur vom Compiler erledigen lassen, wenn du im Programm Zeiger rumreichst, die nicht die Größeninformationen mitschleppen?



  • Mechanics schrieb:

    Aber wie willst du das einsparen und nur vom Compiler erledigen lassen, wenn du im Programm Zeiger rumreichst, die nicht die Größeninformationen mitschleppen?

    Wenn wir vom nicht array-Fall ausgehen, dann steckt die Größeninformation im Typen für den Fall dass der statische Typ dem dynamischen Typ entspricht (also kein delete über einen Zeiger auf eine Basis mit virtuellem Destruktor).

    Für arrays muss die Größe des Arrays zur Laufzeit mit abgelegt werden, weil sich die nicht aus dem Typen ableiten lässt.

    Da haben wir wohl etwas aneinander vorbei geredet, sorry.

    Typen wie std::vector<>, die wahrscheinlich die Hauptnutzer von dynamisch alloziierten arrays sind, kennen die Größe des alloziierten Speichers sogar nochmal explizit, sodass der allocator die Information an der Stelle auch nicht mehr braucht.



  • Torsten Robitzki schrieb:

    Naja, wenn Du sehr viele kleine Objekte hast, deren dynamisch alloziierter Speicher nicht viel größer als sizeof(void*) ist, dann fällt das schon ins Gewicht.

    Sicherlich; je höher die Frequenz von new/delete, desto störender macht sich jeder einzelne Taktzyklus dieser Funktionen bemerkbar. Wer aber auf solche Probleme stößt, der sollte vielleicht bessser mal seinen Programmierstil überprüfen, als auf die Heap-Verwaltung zu schimpfen.

    Torsten Robitzki schrieb:

    Entscheidend ist aber, dass wenn die Größe zur Compiler-Zeit bekannt ist, ich evtl. schon einige Schritte bei der Speicherverwaltung sparen kann.

    Ja, klar. Ein schlauer Compiler wird womöglich für sowas gar nicht erst den Heap benutzen, sondern solche kurzlebigen Miniobjekte im Stackframe speichern, falls sie funktionslokal bleiben, oder gar eine eigene Speicherverwaltung dafür mitbringen.



  • dove schrieb:

    ja, das ist ein fehler im design von C++.
    dem new sagt man die größe, also sollte man dem delete auch die größe sagen (müssen).

    Was ist dein Argument dafür? Symmetrie? Kann ich nicht durchgehen lassen, ist beim Programmieren oft einfach keine gute Idee alles auf Teufel-komm-raus symmetrischen machen zu wollen.
    Mal ganz davon abgesehen dass oft nicht klar ist was "symmetrisch" überhaupt bedeuten soll.

    Man könnte genau so sagen symmetrisch wäre es, wenn man bei new die Grösse angibt und nen Zeiger zurückbekommt, und bei delete den Zeiger angibt und die Grösse zurück bekommt. Wäre aber genau so beknackt (noch beknackter).

    Und...
    Wenn es deiner Meinung gut/korrekt/... wäre dass man bei delete die Grösse mitgeben muss...
    Was ist dann mit fclose()? Sollte man da den Filenamen nochmal angeben müssen? -> Blödsinn.
    Bzw. mit jedem Destruktor eines Objekts dessen Konstruktor man mit bestimmten Parametern aufgerufen hat?

    Nene.
    Der Designfehler ist höchstens dass man die Grösse nicht abfragen kann. Weil die Implementierung sich die Grösse sowieso merken muss (zumindest bei Arrays aus Objekten mit nicht-trivialem Dtor).



  • hustbaer schrieb:

    Nene.
    Der Designfehler ist höchstens dass man die Grösse nicht abfragen kann.

    Das kannst du doch spielend leicht umgehen, indem du sie selber speicherst.
    Jetzt wird es aber albern. 🙄


Anmelden zum Antworten