Frage zu TComponentList und CodeGuard
-
Hallo
Heinzi-kun schrieb:
liste->OwnsObjects hatte ich auf true und false probiert. Hatte leider nichts gebracht.

Spricht eher dafür das CodeGuard ein Problem hat.
Ja das stimmt, aber 0 überprüfen muss doch bleiben, kann ja sein das mal ein Index irgendwo versagt und das Memo nicht mehr existiert ^^
Programmieren hat etwas mit Präzision und Berechnung zu tun. Ein Code wo irgendwo etwas versagt und etwas nicht mehr existiert obwohl es noch gelistet wird ist ein schlechter Code, da helfen auch Überprüfungen nichts.
Den Satz verstehe ich irgendwie nicht. Also grob gesagt habe ich eine GUI mit einem Eingabefeld(Memo) und dort tippe ich etwas rein und sage zum Beispiel "ADD" und will den Inhalt in mein vector<Memo> ablegen, später wieder aufrufen können, speichern, verschieben oder eben wieder löschen. Quasi eine kleine Verwaltung von Texten. Is nur kleiner Test. Das Prinzip brauch ich dann für etwas anderes später noch, ich taste mich so erstmal daran an.
Damit meine ich das Memos die nicht mehr gebraucht werden, erstens gelöscht und zweites der entsprechende Pointer aus dem vector entfernt wird. Damit ist keine weitere Übeprüfung notwendig.
Also ich gehe davon aus das ich in einer Funktion ein Memo erstelle(new) und dieses dann in vector ablege mich nicht mehr um das delete kümmern muss, da der vector bei Programmende das Memo selber sauber entfernt und ich somit auf meinen vector überall im Programm zugreifen kann und meine Memos mit INhalt beleben. Ebenfalls muss ich mich beim vector selbst um kein delete kümmern da er das selber erledigt.
Nein, leider hast du einen Denkfehler drin. In der Tat löscht vector selber alle seine Elemente. In deinem Fall also jeden einzelnen Pointer auf ein Memo. Aber nicht die Memos selber! Der vector löscht also nicht die Memos ansich. In deinem konkreten Fall ist das aber kein Problem da du den Memos beim erstellen einen Owner übergibst (this, also höchstwahrscheinlich das Form). Dieser ist damit fü das löschen zuständig, es entstehen also aus dieser Ecke keine Speicherlöcher. Erst wenn du als Owner NULL übergibst must du in der Tat die Memos manuell löschen. Dann machen weder vector noch Form das für dich.
Ich weiße nochmal darauf hin das Memo eine visuelle Komponente ist. Deine Beschreibung klingt aber so als würde bei dir nichtvisuelle Komponenten wie TStringList ausreichen (weniger unnötiger Overhead)
bis bald
akari
-
akari schrieb:
Nein, leider hast du einen Denkfehler drin. In der Tat löscht vector selber alle seine Elemente. In deinem Fall also jeden einzelnen Pointer auf ein Memo. Aber nicht die Memos selber! Der vector löscht also nicht die Memos ansich. In deinem konkreten Fall ist das aber kein Problem da du den Memos beim erstellen einen Owner übergibst (this, also höchstwahrscheinlich das Form). Dieser ist damit fü das löschen zuständig, es entstehen also aus dieser Ecke keine Speicherlöcher. Erst wenn du als Owner NULL übergibst must du in der Tat die Memos manuell löschen. Dann machen weder vector noch Form das für dich.
Oha! Das schlecht, also ist wohl ComponentList->Clear() doch besser. Ich habe ja die Möglichkeit auch über Menüpunkt "Neu" ein neues Projekt zu starten, dann würde ich irgendwann ja massenhaft von Memos haben, da diese nicht entfernt würden.
Wie lösche ich denn die Memos in <vector>"memos"?
-
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>()); }
-
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... ZugriffsfehlerDas 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.