Fragen zu TList und ListView
-
akari schrieb:
Hallo
Aber das mit dem Speicherleck habe ich noch nicht verstanden. Beim Schließen von Form2 delete ich ja die TList
Das Problem ist, das die TList-Instanz nicht die sogenannte "Ownership" der ihrer Elemente besitzt. Wenn du die TList-Instanz löscht, löscht TList nicht automatisch die Instanzen auf die die Pointer in der Liste zeigen. Das mußt du selber machen.
Und wenn ich in der for-Schleife "Daten" deleten möchte, dann bekomme ich eine Fehlermeldung dass das nicht geht
Das liegt daran das TList nur die void-Pointer kennt, aber nicht weiß was für Instanzen hinter diesen void-Pointern stehen. In C++ aber braucht der delete-Operator unbedingt die genaue Klasse der zu löschenden Instanz. Wenn du also, wie bereits im Beispiel gezeigt, den Zeiger auf den Typ castest, kannst du deine for-Schleife ausführen.
for (...) delete ((Daten*)MeineDaten->Items[lv]);
akari
Nur um es abschließend verstanden zu haben, dann wäre das Speicherleck durch folgende Änderung beseitigt:
void __fastcall TForm2::Button2Click(TObject *Sender) { for ( int i=0; i < MeineDaten->Count; i++ ) { delete ((Daten*)MeineDaten->Items[i]); } if ( MeineDaten ) { delete MeineDaten; } Close(); }
Ist das hier falsch in deinem Bezug auf "Ownership" ? Muss da in die Klammern noch etwas rein ?
MeineDaten = new TList();
Mit der Geschichte vector werde ich mich dann etwas näher befassen
-
Du solltest vor dem Zugriff auf MeineDaten den Zeiger prüfen. Ausserdem solltest du C++ casts benutzen statt C-style casts.
void __fastcall TForm2::Button2Click(TObject *Sender) { if ( MeineDaten ) { for ( int i=0; i < MeineDaten->Count; i++ ) { delete reinterpret_cast<Daten*>( MeineDaten->Items[i] ); } delete MeineDaten; MeineDaten = 0; } Close(); }
Du kannst für TList kein Owner angeben, der sich um die Zerstörung der Liste bzw. deren Inhalt kümmert. Hier ist wirklich Handarbeit gefragt.
trial schrieb:
Mit der Geschichte vector werde ich mich dann etwas näher befassen
Löblich! Du wirst begeistert sein, was man mit der STL so alles anstellen kann und dich fragen, wie du bisher ohne ausgekommen bist.
/Edit akari : Tags korrigiert
-
Was ist da jetzt schiefgegangen?
-
DocShoe schrieb:
Was ist da jetzt schiefgegangen?
[cpp][/cpp] erlaubt keine verschachtelten Tags.
Wärest du registriert, könntest du es ausbessern
-
audacia schrieb:
DocShoe schrieb:
Was ist da jetzt schiefgegangen?
[cpp][/cpp] erlaubt keine verschachtelten Tags.
Wärest du registriert, könntest du es ausbessern
Jaaaaaaa, ich weiß. Ich mich damals beim Registrieren wohl ausgesprochen blöde angestellt, jedenfalls kann ich mich weder mit meinem gewünschten Nick noch meiner Email Adresse registrieren. Hab´ dem Admin vorhin ´ne Mail geschickt, ob man das zurücksetzen kann, dann registriere ich mich auch. Versprochen!
-
Danke ! Da hab ich wieder einiges gelernt
Eine Frage noch ...
DocShoe schrieb:
Du kannst für TList kein Owner angeben, der sich um die Zerstörung der Liste bzw. deren Inhalt kümmert. Hier ist wirklich Handarbeit gefragt.
Wie erkennt man denn ob man einen Owner beim Erstellen mit angeben kann oder nicht ?
-
Hallo
Ein Owner ist auch nur eine Eigenschaft. Ob eine Klasse also eine Owner-Eigenschaft hat und damit deren Konstruktor auch einen entsprechenden Parameter, kannst du in der Builder-Hilfe nachlesen.
bis bald
akari
-
Hallo zusammen,
ich habe mal eine Version mit vector zusammengebastelt und möchte von euch mal hören ob das so ok ist ?
//--------------------------------------------------------------------------- #include <vcl.h> #include <iostream> #include <vector> #pragma hdrstop #include "Unit3.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" //--------------------------------------------------------------------------- using namespace std; const int ANZAHLDATEN = 30000; const int NoOfColums = 3; TForm3 *Form3; vector<string> MeineVectorDaten; //--------------------------------------------------------------------------- string zufallsString() { int length = random(10) + 3; string zstring = ""; char chars [] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; for ( int i = 0; i < length; i++ ) { zstring += chars[ random( strlen(chars) ) ]; } return zstring; } //--------------------------------------------------------------------------- __fastcall TForm3::TForm3(TComponent* Owner) : TForm(Owner){} //--------------------------------------------------------------------------- void __fastcall TForm3::FormCreate(TObject *Sender) { randomize(); //OwnerData auf true setzen, sonst geht das Beispiel nicht ListView1->OwnerData = true; ListView1->RowSelect = true; ListView1->ViewStyle = vsReport; //Drei Spalten einfügen TListColumn *column = ListView1->Columns->Add(); column->Caption = "Index"; column = ListView1->Columns->Add(); column->Caption = "Spalte1"; column = ListView1->Columns->Add(); column->Caption = "Spalte2"; column = ListView1->Columns->Add(); column->Caption = "Spalte3"; //Dummydaten erzeugen for ( int i = 0; i < ANZAHLDATEN; i++ ) { MeineVectorDaten.push_back( IntToStr( i ).c_str() ); MeineVectorDaten.push_back( zufallsString() ); MeineVectorDaten.push_back( zufallsString() ); } //ListView-Inhalt anzeigen FuelleView(); } //--------------------------------------------------------------------------- void __fastcall TForm3::ListView1Data(TObject *Sender, TListItem *Item) { vector<string>::iterator j; if ( Item->Index < MeineVectorDaten.size()/NoOfColums ) { j = MeineVectorDaten.begin() + (Item->Index * NoOfColums); Item->Caption = IntToStr(Item->Index); Item->SubItems->Add( static_cast<AnsiString>( (*j++).c_str() ) ); Item->SubItems->Add( static_cast<AnsiString>( (*j++).c_str() ) ); Item->SubItems->Add( static_cast<AnsiString>( (*j++).c_str() ) ); } } //--------------------------------------------------------------------------- void TForm3::FuelleView() { ListView1->Items->Count = MeineVectorDaten.size()/NoOfColums; ListView1->Items->BeginUpdate(); try { if ( ListView1->Items->Count > 0 ) { //Erste Element markieren ListView1->Selected = ListView1->Items->Item[0]; ListView1->Selected->Focused = true; ListView1->Selected->MakeVisible(false); } } __finally { ListView1->Items->EndUpdate(); } } //--------------------------------------------------------------------------- void __fastcall TForm3::Button1Click(TObject *Sender) { //Weitere Dummydaten erzeugen for ( int i = 0; i < ANZAHLDATEN; i++ ) { MeineVectorDaten.push_back( IntToStr( i ).c_str() ); MeineVectorDaten.push_back( zufallsString() ); MeineVectorDaten.push_back( zufallsString() ); } //ListView-Inhalt anzeigen FuelleView(); } //--------------------------------------------------------------------------- void __fastcall TForm3::Button2Click(TObject *Sender) { Close(); } //---------------------------------------------------------------------------
2 Fragen hab ich noch zusätzlich:
Wie bekomme ich "vector<string> MeineVectorDaten;" aus dem globalen Bereich raus und kann ich anstatt einem string auch 3 strings mit einem push_back Aufruf übergeben ?
-
Hallo
Wie bekomme ich "vector<string> MeineVectorDaten;" aus dem globalen Bereich raus
Du kannst es als Member von TForm3 deklarieren. Ist auch wirklich besser als global. Dazu must du es nur in die Header-Datei verschieben :
// TForm3.h ... #include <vector> // hinzufügen class TForm3 : public TForm { public : private : ... vector<string> MeineVectorDaten; // hinzufügen };
kann ich anstatt einem string auch 3 strings mit einem push_back Aufruf übergeben
Nein
bis bald
akari
-
Hallo akari,
akari schrieb:
Du kannst es als Member von TForm3 deklarieren. Ist auch wirklich besser als global. Dazu must du es nur in die Header-Datei verschieben :
// TForm3.h ... #include <vector> // hinzufügen class TForm3 : public TForm { public : private : ... vector<string> MeineVectorDaten; // hinzufügen };
Wenn ich das so in die Header-Datei übernehme, bekomme ich folgenden Fehler:
25 ... vector<string> MeineVectorDaten; [C++ Fehler] Unit3.h(25): E2303 Typname erwartet [C++ Fehler] Unit3.h(25): E2139 In Deklaration fehlt ;
Wenn ich in der Header-Datei noch zusätzlich "using namespace std;" einfüge, dann compiliert er ohne Fehler, aber ich mal hier im Forum gelesen, dass man "using namespace std;" nicht in die Header-Datei einfügen soll, oder kann man das doch
-
Hallo
Ja das using namespace std sollte besser nicht in einem Header stehen (auch wenn das für dein Projekt wohl kein Einfluß hat).
Ist auch kein Problem das using in der cpp-Datei zu lassen, du must im Header eben nur den Namespace bei vector und string explizit angebenstd::vector<std::string> MeineVectorDaten;
bis bald
akari
-
Danke akari, damit funktioniert es einwandfrei !
Eine Frage noch zu meinem Verständnis:
// Das alleine funktioniert nicht #include <vector> ... vector<std::string> MeineVectorDaten; ............... // Das funktioniert auch nicht und der Compiler sagt vector ist kein Element von std //#include <vector> std::vector<std::string> MeineVectorDaten;
Wenn vector kein Element von std ist, warum brauch ich dann std::vector ?
-
Hallo
std ist ein Namespace. std::vector ist also im Header <vector> für den Namespace std definiert. Du brauchst beide Verweise, um es verwenden zu können, egal ob du using verwendest oder "std::" ausschreibst.
bis bald
akari