delete[], delete????



  • Hallo Leute,

    habe in der MSDN ein wenig über delete nachgelesen und herausgefunden, dass die Klammern (delete[]) genutzt werden, wenn ich ein Array löschen möchte, für das ich Speicher besorgt habe.

    So und nicht anders dachte ich mir dieses bisher auch.

    Doch leider habe ich Problemme mit meinem Code.

    Ich habe eine Klasse, in der ich meine Funktionen, welche ich überall benötige drin untergebracht habe. Von einem Dialog aus rufe ich nun einzelne Methoden dieser Klasse auf indem ich mir zuvor ein Objekt dieser Klasse erstelle.
    Dieses Objekt sollte doch nun ein einfaches Objekt und kein Array sein.
    Nun lege ich mir in meiner Dialogklasse auch einen CString Pointer an, welcher den Rückgabewert (CString Pointer) der Methode des erstellten Objektes aufnimmt. Dieser Pointer sollte doch auch ein einfaches Objekt sein und kein Array.

    Nun habe ich anfänglich beide Objekte (Objekt der Klasse und das Objekt,welches den Rückgabewert aufnimmt) in "OnDblclkAuftragsbox()" durch ein delete[] gelöscht. Dabei kam es zu Speicherfehlern.
    Entferne ich bei beiden deletes die Klammern, so ist der Speicherfehler nicht mehr da.
    Was mich nun verwundert ist die Tatsache, dass ich die Klammern beim delete des Klassenobjektes wieder einfügen kann ohne das es knallt.

    Hat dafür jemand eine Erklärung? (Und bitte bei Vermutungen dies mit angeben, bevor ich etwas als Tatsache annehme und es war nur geraten ;), denn es ist mir wichtig darüber genau Bescheid zu wissen)

    Ich habe noch viele andere Klassen und deletes wo es sich teilweise sehr unterschiedlich mt den Klammern verhält, ohne dass ich ein System erkennen könnte. Es gibt auch Objekte exakt der Klasse des hier beschriebenen Falls, bei dehnen es sich mit den Klammern anders verhält. Eigenartig, da es sich bis auf die Bezeichner nahezu um die gleichen Routinen handelt. Es scheint das selbe zu sein.

    class CSpezialFunktionen : public CDialog
    {
    public:
    	CString* m_Array;
    	CString* DateiHolen(CString Datei, int &anzahl);
    
    	CSpezialFunktionen(CWnd* pParent = NULL);   // standard constructor
    	~CSpezialFunktionen();
    };
    
    CSpezialFunktionen::~CSpezialFunktionen()
    {
    	delete[]m_Array;
    }
    
    CString* CSpezialFunktionen::DateiHolen(CString Datei, int &anzahl)
    {
    	m_Array = new CString[5];
    
    	///////////////////////////////////hier wird m_Array befüllt////////////////////////////
    
    	return m_Array;
    }
    
    #include "Spezialfunktionen.h"
    
    void COffeneJobsWahl::OnDblclkAuftragsbox() 
    {
    	int anzahl = 0;
    	CSpezialFunktionen* Projekt = new CSpezialFunktionen;
    	CString *ArrayProjekt;
    
    	ArrayProjekt = Projekt->DateiHolen(C:\\egal.txt, anzahl);	
    
    	delete ArrayProjekt;
    	delete []Projekt;
    }
    

    VIELEN DANK FÜR JEGLICHE HILFE!!!!!
    Günni



  • Ist eigentlich eine ziemlich einfache Sache. Was du mit new anlegst, gibst du mit delete wieder frei, was du mit new[] anlegst, gibst du mit delete[] wieder frei.



  • Ja so denke ich mir das ja auch.
    Doch was passiert, wenn ich ein new[] mit delete lösche?

    Und warum ist das in meinem Programm so wiedersprüchlich mit den Fehlermeldungen? Warum kann ich, ohne dass es Fehlermeldungen gibt ein mit new angelegtes Objekt mit delete[] löschen???

    Schaue mal Objekt "Projekt" an!!



  • Doch was passiert, wenn ich ein new[] mit delete lösche?

    Ist undefiniert.

    Nun habe ich anfänglich beide Objekte (Objekt der Klasse und das Objekt,welches den Rückgabewert aufnimmt) in "OnDblclkAuftragsbox()" durch ein delete[] gelöscht. Dabei kam es zu Speicherfehlern.
    Entferne ich bei beiden deletes die Klammern, so ist der Speicherfehler nicht mehr da.
    Was mich nun verwundert ist die Tatsache, dass ich die Klammern beim delete des Klassenobjektes wieder einfügen kann ohne das es knallt.

    Beim delete([]) knallts eigentlich nur wenn was mit dem spreicherblock nicht stimmt (du hast drüber hinaus geschrieben, ungülitger pointer, ..)



  • Sorry CMatt,

    könntest Du das mal näher ausführen? Ich verstehe 😮 nix...

    Mit undefiniert meinst DU, dass ich Speicher nicht freigebe??

    Es ist so, dass ich ein mit new erstelltes Objekt einerseits mit delete[] löschen kann ohne das es einen Fehler gibt(wie in obigen Beispiel) und ein anderes Mal gibt es einen Speicherfehler und es funktioniert nur, wenn ich mit einfachem delete lösche.



  • Mit undefiniert meinst DU, dass ich Speicher nicht freigebe??

    Mit undefiniert meint er das alles mögliche passieren könnte. Es könnte der Speicher freigegeben werden, er könnte es nicht. Es könnt etwas völlig anderes passieren.



  • Das heißt manchmal gehts gut und das Programm läuft scheinbar Fehlerlos und das andere Mal gibts Speicherfehler???
    Warum motzt der Compiler nicht direkt, dass es Verkehrt ist?



  • Woher soll das compiler das wissen?
    Versuch mal compiler zu spielen:

    char *p;
    
    if(rand()%10 < 5)
     p = new char[100];
    else 
     p = new char;
    
    delete p; // hmmm... was nehemn wir jetzt? delete oder delete[]
    

    :p

    Das heißt manchmal gehts gut und das Programm läuft scheinbar Fehlerlos und das andere Mal gibts Speicherfehler???

    Wie oben geschrieben, das liegt an dir nicht am compiler. delete[] ist richtig, delete ist falsch, wenns mit delete[] knallt, dann kannst du nicht aufs falsche delete ausweichen sonern musst den Fehler finden.
    Bsp. du schreibst irgendwo über den speicher hinaus und machst dir damit das letzte element in deinem array kaput. delete macht irgend was, und das irgend was führt nicht dazu das dein letztes elemnt gelöscht wird => alles läuft (wie bei dir). delete[] gibts alle elemnte frei => beim letzten knallts weil das kaput ist.



  • Wie oben geschrieben, das liegt an dir nicht am compiler. delete[] ist richtig, delete ist falsch ...

    Hmmm.... auf was beziehst Du Dich nun?

    Muss ich folgendes nicht mit delete anstatt mit delete[] löschen??

    CSpezialFunktionen* Projekt = new CSpezialFunktionen;
    


  • Hmmm.... auf was beziehst Du Dich nun?

    ->

    Beim delete([]) knallts eigentlich nur wenn was mit dem spreicherblock nicht stimmt (du hast drüber hinaus geschrieben, ungülitger pointer, ..)

    Muss ich folgendes nicht mit delete anstatt mit delete[] löschen??

    jo

    new ==> delete
    new[] == delete[]



  • Beim delete([]) knallts eigentlich nur wenn was mit dem spreicherblock nicht stimmt (du hast drüber hinaus geschrieben, ungülitger pointer, ..)

    Ooooh man, habe mich ein wenig von meinem Rechner wegbewegt und den Satz dann zum xten Mal angeschaut. Und siehe da: jetzt wird mir der Sinn klar. Ich hatte ihn zuvor ganz anders verstanden. Irgendwie fehlt mir da ein "z.B." in der klammer. Hatte es so verstanden als läg da mein Fehler und nicht als allgemeinen Satz. Ist eine harte Woche ... 🙄



  • da fehlt kein z.b, sondern ich war einfach zu fault "delete oder delete[]" zu schreiben :p



  • Die Erklärung mit dem "char *p" war übrigens sehr einleuchtend.

    Doch schaut Euch bitte mal meinen Code genauer an. Ich denke mein Fehler liegt darin, dass ich den Speicher fürs Array im Destructor lösche. Kann es sein, dass ich die Sache mit den Pointern falsch angehe?

    Hättet Ihr da eine bessere Idee?



  • z.B. => 2te Klammer!! 😉



  • Hi, ein paar vorschläge von mir....

    class CSpezialFunktionen : public CDialog // warum ?? ist das nötig?
                                              // ansonsten weg damit und vielleicht eine Singletonklasse von machen!
    { 
    public: 
        CString* m_Array; // braucht man nicht => weg damit (ist deine Speicherverletzung!)
        CString* DateiHolen(CString Datei, int &anzahl); 
    
        CSpezialFunktionen(CWnd* pParent = NULL);   // standard constructor 
        ~CSpezialFunktionen(); 
    }; 
    
    CSpezialFunktionen::~CSpezialFunktionen() 
    { 
        delete[]m_Array; // auch wech damit *puff*
    } 
    
    CString* CSpezialFunktionen::DateiHolen(CString Datei, int &anzahl) 
    { 
        CString* pArray = new CString[5]
        //m_Array = new CString[5]; 
    
        ///////////////////////////////////hier wird m_Array befüllt//////////////////////////// 
    
        //return m_Array; 
        return pArray;
    } 
    
    #include "Spezialfunktionen.h" 
    
    void COffeneJobsWahl::OnDblclkAuftragsbox() 
    { 
        int anzahl = 0; 
        CSpezialFunktionen* Projekt = new CSpezialFunktionen; // wäre bei Singleton nicht nötig und spart Zeit bzw. Resourcen
        //CString *ArrayProjekt; 
    
        CString* pArrayProjekt = Projekt->DateiHolen(C:\\egal.txt, anzahl);    
    
        delete []pArrayProjekt; 
        delete Projekt; // fällt auch raus bei Singleton
    }
    

    Wenn du das array in OnDblclkAuftragsbox löscht und dann das Projekt löscht,
    löscht du das Objekt zweimal (s. Destruktor in der Spezialklasse) ! Das kann nicht gut gehen.

    Singleton würde ich mir mal anschauen: http://gethelp.devx.com/techtips/cpp_pro/10min/10min0200.asp



  • void COffeneJobsWahl::OnDblclkAuftragsbox() 
    { 
        int anzahl = 0; 
        CSpezialFunktionen* Projekt = new CSpezialFunktionen; 
        CString *ArrayProjekt; 
        // soweit alles klar
    
        // DateiHolen macht ein new CString[5] und gibt nen pointer zurück
        ArrayProjekt = Projekt->DateiHolen(C:\\egal.txt, anzahl);    
    
        // du löscht dein string array 
        // Fehler: es ist ein array also delete[]
        delete ArrayProjekt; 
    
        // du löscht dein CSpezialFunktionen obejct
        // 1. Fehler: es ist ein einzelnes object also delete
        // 2. Fehler: der destroctur von CSpezialFunktionen mach ein 
        //            delete auf ein string-array, das gibts aber mitlerweile
        //            nimmer da du bereits selbst delete ArrayProjekt aufgerufen
        //            hast
        delete []Projekt; 
    }
    

    Anmrekungen:
    - Was macht der construtor von CSpezialFunktionen? Setzt der m_Array auf 0? Falls nicht knallts sollest du mal irgendwann DateiHolen nicht aufrufen (ein delete[] call auf nen pointer ins nirvana)
    - Wenn du beim delete im destructor bleist. Was passiert wenn du DateiHolen öfter aufrufst? Zur zeit: speicherleck.



  • Boa, viele Infos auf einmal!

    habe gleich Feierabend und schaff leider nicht mehr alles.
    Werde Montag voll dran gehen und alles aufarbeiten.
    Singleton ist mir völlig unbekannt, hört sich aber auf den ersten Blick (Threat, etc...) gut an.
    Danke!!

    Aber eine Frage habe ich jetzt noch ...

    // du löscht dein string array
    // Fehler: es ist ein array also delete[]
    delete ArrayProjekt;

    Warum handelt es sich hierbei um ein Array? Der Name ist nur willkürlich.

    CString *ArrayProjekt;

    Die Sache mit den Mehrfachaufrufen der Klasse und denn Speicherlecks dadurch ist sehr informativ, sowie die Sache mit dem Objekt erstellen ohne Speicher zu besorgen bevor ich versuche sie im Destruktor zu löschen.

    Sehr informativ!!

    Schönes Wochenende und bitte noch die eine Frage beantworten 😃



  • Das ArrayProjekt ein Array ist, sieht man nur weil es im Code so geschrieben ist.

    CString* CSpezialFunktionen::DateiHolen(CString Datei, int &anzahl) 
    { 
        CString* pArray = new CString[5] // erzeuge array of CString
        //m_Array = new CString[5]; 
    
        ///////////////////////////////////hier wird m_Array befüllt//////////////////////////// 
    
        //return m_Array; 
        return pArray; 
    }
    

    Der Aufrufer kann das nicht wissen, genausowenig wie das er den Speicher
    freigeben muss und das auch noch mit der delete[] Anweisung.

    Ich habs mal so gelassen, um nicht zu viel auf einmal zu ändern,
    aber Du merkst schon, das hier ein designproblem vorliegt.

    Du könntest ja vielleicht ein CPtrArray zurückliefern...



  • Guten Morgen,

    genau da liegt mein Problem!!!
    Ist ein einfacher CString Pointer automatisch ein CString Array Pointer sobald dieser durch einen Rückgabewert ein solches übergeben bekommt?

    Hmmmmm ... schwer zu erklären!!!
    Also: In der Methode "DateiHolen" lege ich ein CString Array "p_Array" an. Dieses gebe ich per Return zurück auf meinen CString Pointer "ArrayProjekt".
    Ist nun automatisch "ArrayProjekt" dadurch auch ein ArrayPointer?

    Denn p_Array wollte ich ja ursprünglich extra im Destructor löschen und dann denn Zeiger "ArrayProjekt" mit einfachem delete.

    Weil wie ihr sagt werden einfache mit delete und Arrays mit delete[] gelöscht.

    Und wenn es nun so ist, muss ich dann nur "ArrayProjekt" löschen oder doch beide?



  • Wie wäre es denn damit

    CString* pArray = new CString[5] 
    
    //Freigabe
    if(pArray!=NULL)
       pArray=NULL;
    
    delete [] pArray;
    

    oder habe ich was übersehen


Anmelden zum Antworten