Frage zu TComponentList und CodeGuard



  • Du löschst die memos mit delete bevor du sie aus dem vector entfernst. Also wenn du das Element i entfernen willst:

    vector<TMemo*> memovect;
    // irgendwelcher Code
    delete memovect[i];
    memovect.erase(memovect.begin()+i);
    

    Wenn du den vector ganz löschen willst, mußt du dein delete in einer Schleife aufrufen.



  • Das ganze löschen geht auch super mit einem Template:

    template <class T>
    class delete_it_obj
    {
    	public:
    		T operator() (T item)
    		{
    			delete item;
    			return 0;
    		}
    };
    template <template <class A> class container_type, class T> 
    void delete_it(container_type<T> &sequence) 
    { 
    	std::transform(sequence.begin(), sequence.end(), sequence.begin(), delete_it_obj<T>());
    }
    

    Quelle: http://groups.google.de/group/borland.public.cppbuilder.language/browse_thread/thread/c5c1e906e43a0f79/5a1298a953f771f2?lnk=st&q=How+to+delete+std%3A%3Avector+pointers%3F&rnum=1&hl=de#5a1298a953f771f2



  • Ich komme da irgendwie nicht mehr ganz mit. 🙄

    Ich würde gern mal zum Anfang zurückgehen, falls CodeGuard einfach nen Bug hat.
    Das mit dem TMemo, welches zur Entwicklungszeit auf die TForm gesetzt wurde verstehe ich mit dem freigeben, aber das mit der zur Laufzeit mit new angelegten nicht.

    Ich möchte beliebige Komponenten mit new erstellen und in eine Liste einfügen. Vorzugsweise TComponentList *MeineListe, da diese extra dafür gemacht wurde.
    Da die Komponenten in einer Funktion neu erstellt werden, gibt es kein delete, diese werden dann ja am Ende des Programmes mit "delete MyListe" alle entfernt.

    Im Header meiner TForm steht im

    private:
        TComponentList *MeineListe;
    

    In der Unit steht (grob, da per Hand eben getippt)

    void __fastcall TForm1::FormCreate(TObject *Sender)
    {
        // MeineListe initalisieren
        MeineListe = new TComponentList;
    }
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
        // Füge bei jedem Klick auf den Button eine
        // TImage Komponente der MeineListe hinzu
        // Auf jede TImage Komponente in MeineListe kann ich seperat zugreifen und darauf zeichnen
        // Freigabe erfolgt über "delete MeineListe" in FormClose
        TImage *MyImage = new TImage(this);
        MeineListe->Add(MyImage);
    }
    void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
    {
        // Wenn (MeineListe!=NULL) dann enthält diese Komponenten
        // mit delete werden all ihre Listen(Komponenten)einträge entfernt und
        // MeineListe ebenfalls freigegeben
        if (MeineListe) delete MeineListe;
    }
    

    So habe ich es gemacht (um mal was anderes als TMemo zu nehmen, soll ja mit allem gehen). Und so müsste es doch auch fehlerfrei sein oder missverstehe ich da etwas?

    Ich kann beliebe Komponenten mit new in die TComponentList werfen und muss mich nicht um deren delete kümmern, da dieses mit "delete MeineListe" ebenfalls sauber entfernt werden.

    Ich verstehe da nicht was CodeGuard rummuckt. 🙄



  • Um bei dem Beispiel mit new TImage(this) zu bleiben... Durch das this gibst Du einen Owner an. Dieser ist für das Löschen verantwortlich. Wenn Du die TImage-Objekte aus Deiner Lister heraus löschen möchtest, darfst Du keinen Eigentümer angeben, oder mußt die Liste so anlegen, dass nur die Pointer gelöscht werden, aber nicht die Instanzen.

    In allen Projekten, die ich so gemacht habe, hatte der CodeGuard schlußendlich immer recht, auch wenn das Programm scheinbar korrekt funktionierte.



  • Mhh, um mal das für mich nachvollziehbar zu machen, bleib ich jetzt bei dem TMemo da ich jetzt die Umgebung zum testen dafür zur Hand habe.

    Ich habe also ein leeres Projekt, dort plaziere ich eine Memo zur Entwicklungszeit rein. In den Header kommt

    private:	// Anwender-Deklarationen
    TComponentList *liste;
    

    und in Unit

    void __fastcall TForm1::FormCreate(TObject *Sender)
    {
        liste = new TComponentList;
        liste->OwnsObjects = false;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
    {
        delete liste;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
        TMemo *Memo = new TMemo(this);
        Memo->Visible = false;
        Memo->Parent = Form1;
        liste->Add(Memo);
    }
    

    Ich sage meiner TComponentList das er nicht für das löschen der Komponenten zu sorgen hat (mittels liste->OwnsObjects = false).
    Über ButtonClick füge ich eine mit new erstellte Komponente in die TComponentenList hinzu.. da es mit dies mit this passiert muss ich mich um die Löschung nicht kümmern, da dies TForm1 selbst beim beendet sauber enternt.

    Soweit schön und gut, aber wieso meckert dann CodeGuard über die Zeile "delete liste;"?
    Wenn ich das "delete liste" weg lasse .. dann meckert CodeGuard nicht und sagt alles roger. Verstehe ich nicht. Habe doch keinen Owner angegeben, also muss delete rein. 🙄



  • Zusatzfrage zur obigen.

    Ich möchte aber zwischendurch die Komponentenliste leeren, weil ich von vorn anfangen möchte. Dann wäre dies legitim?

    void __fastcall TForm1::ResetClick(TObject *Sender)
    {
        liste->OwnsObjects = true;
        liste->Clear();
        liste->OwnsObjects = false;
    }
    

    Er soll damit alle Objete in der TComponentList entfernen und die Einträge auch alle. So das ich neue Memos einfügen kann und sich während der Arbeit mit dem Programm nicht im Hinterfrund plötzlich hunderte nicht benutzte Memos ansammeln. 😉

    CodeGuard meldet zwar keinen Fehler, aber das muss ja nicht heissen das es richtig ist.



  • Hallo

    Heinzi-kun schrieb:

    Ich habe also ein leeres Projekt, dort plaziere ich eine Memo zur Entwicklungszeit rein. In den Header kommt
    ...
    Wenn ich das "delete liste" weg lasse .. dann meckert CodeGuard nicht und sagt alles roger. Verstehe ich nicht. Habe doch keinen Owner angegeben, also muss delete rein. 🙄

    Du verwendest OnCreate und OnClose. Damit hast du schon mal ein Problem, denn die beiden Events gehören nicht zusammen. Die korrekten Paare sind OnCreate/OnDestroy und OnShow/OnClose. Bei dir wäre theoretisch der Ablauf denkbar
    - Instanz des Forms wird erstellt : Aufruf von OnCreate, Liste wird erstellt
    - Instanz wird angezeigt : Aufruf von OnShow
    - Form wird geschlossen : Aufruf von OnClose, Liste wird gelöscht
    - Form wird wieder angezeigt : Aufruf von OnShow, Zugriff auf Liste... Zugriffsfehler

    Das tritt bei dir so nicht auf weil dein Form das Hauptformular ist und beim Schließen gleich die Anwendung beenden. Darauf darfst du dich aber nicht verlassen. Denk immer dran : Ein geschlossenes (nicht sichtbares) Form heißt noch lange nicht das es wirklich gelöscht wird oder das die Anwendung beenden wird.
    Kann schon sein das CodeGuard dieses Problem sieht trotz das es praktisch bei dir nicht ausgelöst wird.

    Übrigens ein weiter Grund OnCreate und OnDestroy nicht zu benutzen : Verwechslungsgefahr mit OnShow/OnClose.

    ch möchte aber zwischendurch die Komponentenliste leeren, weil ich von vorn anfangen möchte. Dann wäre dies legitim?...

    Sollte in Ordnung sein.

    bis bald
    akari



  • Danke für deine umfangreiche Antwort!

    Das mit Create/Destroy und Show/Close behalte ich im Hinterkopf, habe es mal entsprechend geändert.

    Bleibt aber die Frage warum muss ich kein "delete liste" ausführen?
    In diesem Fall ist es egal ob es im Close oder Destroy steht, der Fehler bleibt der Selbe.

    Wenn ich Create nicht benutzen sollte, dann soll ich das direkt ins "__fastcall TForm1(TComponent* Owner);" eintragen?

    Es existiert aber kein Destructor in der TForm1 Klasse. Der wird wohl in der abgeleiteten TForm Klasse liegen.
    Muss ich jetzt VCL korrekt ein "__fastcall ~TForm1();" einfügen und dort meine Freigaben tätigen, oder wie sonst? 🤡



  • Hallo

    Bleibt aber die Frage warum muss ich kein "delete liste" ausführen?
    In diesem Fall ist es egal ob es im Close oder Destroy steht, der Fehler bleibt der Selbe.

    Ich kann das Verhalten nicht nachvollziehen. Auf meinem BCB5 habe ich dein Test ausprobiert und folgendes festgestellt :
    - Ohne CodeGuard kommen keine Probleme
    - Mit CodeGuard wird egal ob OnDestroy oder Destruktor bei delete liste eine Speicherzugriffsverletzung angezeigt, aber nur wenn ein Memo in die liste eingetragen wurde.
    Das deutet eher auf ein internes Problem CodeGuard/VCL hin.

    Wenn ich Create nicht benutzen sollte, dann soll ich das direkt ins "__fastcall TForm1(TComponent* Owner);" eintragen?

    In die Implementation des Konstruktors, ja.

    Es existiert aber kein Destructor in der TForm1 Klasse. Der wird wohl in der abgeleiteten TForm Klasse liegen.
    Muss ich jetzt VCL korrekt ein "__fastcall ~TForm1();" einfügen und dort meine Freigaben tätigen, oder wie sonst? 🤡

    Ja, der Destrukor muß manuell hinzugefügt werden.

    bis bald
    akari



  • Ah, danke!
    Also muss das delete liste; wieder rein und muss mir wegen des Fehlers von CodeGuard keine gedanken machen. 😉



  • Ja, doch. In deinem ersten Post hast Du die Fehlermeldungen mit angegeben. Dort war das Problem definitiv, dass die Objekte die freigegeben werden sollten, zu diesem Zeitpunkt bereits freigegeben waren.


Anmelden zum Antworten