delete[]



  • Hallo zusammen
    Ich habe eine Frage, die mir nicht aus dem Kopf geht:

    int sm[64]; // static memory
    cout << sizeof(sm)/sizeof(int); // 64
    
    int *dm = new int[64]; // dynamic memory
    cout << sizeof(dm)/sizeof(int); // 1
    

    Wie kriege ich die Grösse des dynamischen Feldes ?
    Ich höre immer wieder sagen, dass dies nicht möglich sein, wenn man aber einmal genau darüber nachdenkt, muss dies schon möglich sein, denn wie könnte sonst folgende Anweisung funktionieren ?

    delete []dm;
    

    Wie sollte das Programm sonst wissen, wie viel Speicher freizugeben ist ?
    Der Compiler kann es ja nicht wissen, da die grösse von dm zur Compilezeit unbekannt ist...

    Gruss Ishildur



  • Ach ja, als Beweis habe ich folgendes Programm geschrieben:

    #include <conio.h>
    
    char *p;
    
    int main(){
     while(!kbhit()){
      p = new char[16777216];
       delete []p;
     }
    
     return 0;
    }
    


  • Wenn Du dir die Implementation des delete-Operators genau ansiehst wirst du fest stellen, das es nur 2 gibt, nämlich

    void operator delete(void*);
    void operator delete[](void*);
    

    Daher kann der Operator nicht einmal von char und int unterscheiden. Muss er auch nicht, denn die größe des Reservieren Speicherplatzes ist im Speicher Manager des Betriebsystems festgehalten.



  • Genau das wollte ich wissen !
    Wenn die grösse des reservierten Speichers festgehalten wird, dann ist es doch auch kein Problem, diese Grösse zur Laufzeit abzufragen ???

    Wieso sehe ich dann immer wieder solche Konstrukte ?

    RECT rect;
     memset(&rect,0,sizeof(RECT));
    

    oder

    RECT rect[4];
     drawRects(rect,4);
    

    Dann müsste doch memset eigentlich problemlos in der Lage sein, die grösse von RECT selbst herauszufinden bzw. drawRects müsste die Anzahl der RECT strukturen selbst ermitteln können ??? 😕



  • Theoretisch währe das auch Möglich. Aber das währe auch viel zu Langsam. Da man jedesmal den Speicher-Manager berappen müste. Da ist es viel schneller einfach die Größe mit sizeof zu ermitteln, oder per Parameter auf den Stack zu legen.

    Zum anderen ist dein Beispiel nicht ganz passend. Locale Variablen können auch in den CPU-Registern landen, und sind damit nicht im Speicher-Manager verzeichnet. So mit kann memset nicht immer die Größe eines Speicherbereichs über den Speicher-Manager ermitteln.

    Des weiteren ist es auch eine Frage wie eine Sprache konzipiert wurde. Bei C und C++ gibt es für Speicherzugriff einfach keine Bereichsprüfung. Man kann also ohne weiteres so was machen

    int i = 0x00FF0000;
    char* c = ((char*)&i)+6;
    

    Damit liege ich zwar auserhalb des Bereichs, was zu einem Programmabbruch führen wird, aber von Seitens C und C++ ist alles korrekt.

    Aber du kannst dir ja ein eigenes Memset basteln 😉

    template<class TYPE> void MyMemset(TYPE* p, int value)
    {
    memset(p, value, sizeof(TYPE));
    }
    


  • Original erstellt von Ishildur:
    einmal genau darüber nachdenkt, muss dies schon möglich sein, denn wie könnte sonst folgende Anweisung funktionieren ?

    fast korrekt.
    klar macht new[] so nen zaubertrick.
    versuch mal

    int* p=new int[10];
    cout<<p[-1]<<endl;
    cout<<p[-2]<<endl;
    ...
    delete[] p;
    

    usw.

    kann sein, daß dein compiler die größe dort ablegt.
    kann aber auch sein, daß er klug ist und für verwaltung nen anderen speicherbereich nimmt. man mag meinen, ne hashtable oder ein trie, die von den daten zu deren verwaltung hüpft, kostet viel, aber naja, die datenlokalität geht hoch, was ja heutzutage oft mehr bringt. dann kannst nur noch mit ganz bösen tricks drankommen.
    und natürlich kann er in obigem beispiel aufs speichern der größe ganz verzichten, weil sie ihm beim löschen ja noch bekannt ist.



  • Abgesehen davon, dass es nun wirklich nicht das Problem ist, sich die Grössen selbst allozierter Bereiche zu merken, wenn Du die Standarddatenstrukturen der STL nimmst, die geben meistens Informationen über die Grösse. Sowie sich Dir jenes Problem stellt, stimmt was mit Deinem Layout nicht.



  • int sm[64]; // static memory
    cout << sizeof(sm)/sizeof(int); // 64

    int *dm = new int[64]; // dynamic memory
    cout << sizeof(dm)/sizeof(int); // 1

    Schreibe

    int *dm = new int[64]; // dynamic memory
    cout << sizeof(*dm)/sizeof(int); // 64
    

    Sollte gehen!



  • nö, da kommt 1 raus.



  • Original erstellt von Bitsy:
    Abgesehen davon, dass es nun wirklich nicht das Problem ist, sich die Grössen selbst allozierter Bereiche zu merken, wenn Du die Standarddatenstrukturen der STL nimmst, die geben meistens Informationen über die Grösse. Sowie sich Dir jenes Problem stellt, stimmt was mit Deinem Layout nicht.

    diagnose ist voreilig.
    wenn du nicht ein schlechtes gefühl hast, wenn du die redundanz siehst, wie die stl-typen selber speichern und der allokator nochmal speichert, stimmt was mit deiner programmiererei auch net.



  • @Bashar: Stimmt! Ist ja auch logisch, denn der Zeiger bezieht sich ja auf das erste Element im Array 😉



  • wenn du nicht ein schlechtes gefühl hast, wenn du die redundanz siehst, wie die stl-typen selber speichern und der allokator nochmal speichert, stimmt was mit deiner programmiererei auch net.

    Gibt es für diesen Satz auch eine allgemein verständliche Übersetzung?
    So wie ich den Satz verstehe, ist er quatsch. Und das ist für mich schwer vorstellbar.

    [ Dieser Beitrag wurde am 01.04.2003 um 15:41 Uhr von HumeSikkins editiert. ]



  • Original erstellt von HumeSikkins:
    Gibt es für diesen Satz auch eine allgemein verständliche Übersetzung?

    irgendwo speichert der new[] die größe eines arrays mit nichttrivialem destruktor ab und manchmal sieht man typen, die zusätzlich zu einem mit new[] angelegten array auch noch dessen größe speichern. das ist doppelte speicherung und sollte einem mißfallen.

    es mag quatsch sein, weil in der stl nirgends der new[] verwendet wird.



  • Warum sollte der new-Operator die Größe eines Speicherblocks zusätzlich irgendwo ablegen? Das währe doch blödsinn, weil eine Speicheranforderung an das Betriebsystem geht, und nicht dem new-Operator überlassen wird. Dann könnte das Betriebsystem auch gar nicht den Speicher überwachen. Wenn legt der BS-Speicher Mgr die größe eines Speicherblocks irgendwo ab.

    zumal spielt es keine solle ob man nun den new oder new[] Operator verwendet. Beide machen absolut das selbe. Ob ich nun

    int* p = new int[10];
    

    mache oder

    int* p = operator new(sizeof(int)*10);
    

    spielt keine Rolle. Erstere ist nur einfacher 😉 zweitere varainte wird übrigens von der STL verwendet.



  • LOL!

    a) das BS gibt Dir nur ganze Seiten von zum Beispiel. 4096 Bytes.
    b) delete[] muß so viele destruktoren aufrufen, wie da objekte sind, dazu muss ne zahl gespeichert sein.
    c) int* p = new int[10]; und int* p = operator new(sizeof(int)*10); mögen für int gleich sein, aber wer redet davon, daß man nur ints hat?



  • Original erstellt von DragonMaster:
    weil eine Speicheranforderung an das Betriebsystem geht, und nicht dem new-Operator überlassen wird.

    Falsch. Das mag bei einzelnen Implementationen so sein, schließlich macht der Standard keine Aussage darüber. Aber bei den Betriebssystemen die ich kenne würde das nicht funktionieren (DOS, Unix). Die Runtime benutzt natürlich die OS-Funktionen, um mehr Speicher zu bekommen. Aber in einer anderen Granularität als du new anwendest. Das ist wie mit dem std::vector ... ein einzelnes push_back führt idR nicht zur Neuallokation, das passiert erst, wenn eine bestimmte Schwelle überschritten wird.



  • @Volkard
    Ok. Hatte deinen Satz falsch verstanden. Dachte du meintest der Allokator würde zusätzlich zum Container noch die Größe speichern.

    Auf der anderen Seite finde ich deinen Einwand etwas merkwürdig. Schließlich gibt es keine portable Möglichkeit an die durch den op new erzeugte Information zu kommen.
    Das ist zwar schade, aber solange es die Realität ist, sehe ich irgendwie nicht wie man um das Speichern der Größe drum rum kommt.



  • Original erstellt von HumeSikkins:
    Auf der anderen Seite finde ich deinen Einwand etwas merkwürdig. Schließlich gibt es keine portable Möglichkeit an die durch den op new erzeugte Information zu kommen.
    Das ist zwar schade, aber solange es die Realität ist, sehe ich irgendwie nicht wie man um das Speichern der Größe drum rum kommt.

    Ja, es ist schade. Man hat ein ungutes Gefühl dabei, daß man nicht ran darf. Es wäre doch so fein, wenn man dürfte. usw.
    Und natürlich ist es legitim, zu fragen: "wie kommt man denn da ran?".
    Wir wissen ja, daß es keinen portablen Weg gibt.
    Aber da schrieb einer "Sowie sich Dir jenes Problem stellt, stimmt was mit Deinem Layout nicht."
    Und das hielt ich für ein wenig gar oberdreist. Also schrieb ich ihm, daß er nen knall hat, wenn er nichtmal das legitime anliegen sieht.

    ich wünschte mir auch machmal, daß es einen legitimen weg gäbe.



  • wenn man die groesse will ist eine

    template <class Type>
    class YAarray{
    private:
    T *varray;
    int size;
    public:
    // konstruct init access destuct hier//
    };

    mit weniger aufwand zu haben
    wenn man das globale ueberwachungs Konzept nutzen wuerde muesste man ja suchen und da is die eine variable mehr nich schlimm.



  • Das Problem warums nicht geht (hat mir mal einer von Euch hier erklärt) ist doch, dass es sein kann, dass new z.B. einen größeren Block belegt, als man anfordert, weils schneller sein kann immer 32-Bit-Blöcke o.ä. zu reservieren.
    Und das ist natürlich System- und Implementierungsabhängig.

    Der Wert, der für das delete[] also irgendwo gespeichert wird ist also >= dem angeforderten und würde einem in den meisten Fällen nicht weiterhelfen. Der angeforderte wird hingegen nirgens gespeichert, weswegen man ihn extra speichern muss -> das ist keine redundante Datenhaltung

    Hat man allerdings ein dynamisch wachsendes Array, wärs aber vielleicht gerade nützlich den tatsächlich reservieren Speicher zu kennen.


Anmelden zum Antworten