Lebensdauer von String Listen
-
Guten Tag,
ich habe mal eine Frage zur Lebensdauer von Stringlisten wenn sie über ein Ereignis hinaus verwendet werden sollen, also nicht klassisch "Anlegen, Verwenden, Freigeben".
Wenn ich die Stringliste in meine Klasse aufnehme kann ich sie nicht am Ende einfach deleten, selbst ein einfaches stringliste->Clear() wird Stellenweiße mit einem Access Error bestraft.
Beschreibung: Im onreceive Ereignis eines UDP Sockets werden die übermittelten Strings in die StringListe aufgenommen. Da die informationen über mehrere Packete gesendet wird wird auch das onreceive mehrmals ausgelöst, logisch. Wie kann ich in dem Falle die Stringliste gescheit "Anlegen,Verwenden,Verwenden,Verwenden,Freigeben" ??
Erster Erfolg:
Ich habe das Problem mit einer global angelegten Stringliste versucht zu lösen, auch das Füllen der Stringliste ist kein Thema, auch das es über mehrmals ausgelöste Ereignisse funktioniert. Doch ab und an wenn ich vor einer neuen Verwendung der Stringliste deren inhalt mit stringliste->Clear() lösche um eben eine leere Liste zu erhalten bekomme ich ab und denn einen ganz Merkwürdigen Access Error
hundert mal funktioniert der Code und beim nächsten mal gibts wieder nen Acess Error.Wenn ich stringliste->Clear() weglasse läuft der Code wie ne 1.

Für kleine Codebeispiele wäre ich sehr dankbar weil ich wegen diesem Problem kurz davor bin in eine geschlossene Psychatrie eingeliefert zu werden da mich das Problem schon fast einen Monat lang nervt. HELP !!!
-
Zero01 schrieb:
Für kleine Codebeispiele wäre ich sehr dankbar
Ditto

Also ich verwende - wie vermutlich viele andere hier auch - häufig TStringList, auch als Membervariable, die im Konstruktor erstellt
und im Destruktor wieder gelöscht wird. Ich kann auch Deine gelegentlichen Probleme mit Clear() nicht nachvollziehen.Das beste wäre es folglich, wenn Du mal zeigen würdest, was Du bisher so angestellt hast.
Gruß,
Alexander
-
Zero01 schrieb:
Wenn ich stringliste->Clear() weglasse läuft der Code wie ne 1.

Sieht so aus, als wuerde Dein Ereignis und das Clear 'gleichzeitig' auftreten koennen. wird Dein Ereignis in einem Thread ausgelöst? Dann koennte es an fehlender synchronisierung liegen.
-
Hast du dich schon mal ernsthaft mit C++ und StringListen beschäftigt??? 
Sorry, aber Objekte gibt man mit delete wieder frei.Oder hast du die StringList nicht so angelegt???
TStringList *abc;und irgendwo anders
abc = new TStringList;Mit abc->Clear() löschst du nur den Inhalt der Liste;
-
@ Gast#649237
Danke für deine Tips, aber das weiß ich schon und habe alles so wie beschrieben angewendet.Ich würde ja gerne mit delete die StringListe wieder freigeben aber das geht nur wenn ich sie Lokal in einer Funktion initialisiere, verwende und wieder freigebe. Die StringListe muss aber Funktionsübergreifend verfügbar sein weshalb ich die unsaubere weiße der globalen Deklaration gewählt habe. Hätte ich sie in die Klasse aufgenommen hätte ich ein Problem mehr gehabt.
Der Tip mit der synchronisation klingt plausibel aber ich verwende strigliste->Clear bevor ich die Funktion "GetServerInfo(int)" aufrufe.
Global: TStringList *player = new TStringList;
void __fastcall TForm1::ListView2SelectItem(TObject *Sender, TListItem *Item, bool Selected) { GameBrowser var; //Klasse GameBrowser if (Item->Selected) { player->Clear(); Form1->ListView1->Clear(); var.GetServerInfo(Item->Index); } }void GameBrowser::GetServerInfo(int index) { String ip = "",iptemp = "",porttemp = ""; GameBrowser var; ip = serverliste->Strings[index]; for (int z = 1; z <= ip.Length(); z++) { if (ip[z] != ':') { iptemp = iptemp + ip[z]; } else { z++; for(int a = z;a <= ip.Length();a++) { porttemp = porttemp + ip[a]; } z = ip.Length(); } } var.SendUDPData(iptemp,StrToInt(porttemp),2555,"xff\\status\\"); }void __fastcall TForm1::UDPStatus1DataReceived(TComponent *Sender, int NumberBytes, AnsiString FromIP, int Port) { char buf[5000]; int lenght,e; AnsiString data,temp = ""; bool value; GameBrowser var; Form1->UDPStatus1->ReadBuffer(buf,5000,lenght); data = AnsiString(buf); for (int r = 1;r <= strlen(data.c_str()) ;r++) { if(data[r] != '\\') { temp = temp + data[r]; //Zusammensetzen jeder Zeile } else { if (temp != "") { if(temp != "queryid") { if(temp.AnsiPos("final") == 1) { value = true; } else { player->Add(temp.c_str()); //Hinzufügen zu Player String Liste temp = ""; } } } } } //------------------------------------------------------- if (value == true) //Wenn die Liste fertig empfangen wurde { int rownumber = -1; for (e = 0; e < player->Count; e++) //Durch Stringliste iterieren { if(player->Strings[e].AnsiPos("deaths_") == 1) //Neuen Spieler in Liste erkennen und ID berechnen { rownumber++; ListView1->Items->Add(); ListView1->Items->Item[rownumber]->Caption = rownumber + 1; ListView1->Items->Item[rownumber]->SubItems->Add(""); ListView1->Items->Item[rownumber]->SubItems->Add(""); ListView1->Items->Item[rownumber]->SubItems->Add(""); ListView1->Items->Item[rownumber]->SubItems->Add(""); ListView1->Items->Item[rownumber]->SubItems->Add(""); ListView1->Items->Item[rownumber]->SubItems->Add(""); ListView1->Items->Item[rownumber]->SubItems->Add(""); } if(player->Strings[e].AnsiPos("deaths_") == 1) ListView1->Items->Item[rownumber]->SubItems->Strings[3] = player->Strings[e + 1]; //Death if(player->Strings[e].AnsiPos("keyhash_") == 1) ListView1->Items->Item[rownumber]->SubItems->Strings[6] = player->Strings[e + 1]; //Hashkey if(player->Strings[e].AnsiPos("kills_") == 1) ListView1->Items->Item[rownumber]->SubItems->Strings[2] = player->Strings[e + 1]; //Kills if (player->Strings[e].AnsiPos("ping_") == 1) ListView1->Items->Item[rownumber]->SubItems->Strings[4] = player->Strings[e + 1]; //Ping if(player->Strings[e].AnsiPos("playername_") == 1) ListView1->Items->Item[rownumber]->SubItems->Strings[0] = player->Strings[e + 1]; //Name if(player->Strings[e].AnsiPos("score_") == 1) ListView1->Items->Item[rownumber]->SubItems->Strings[1] = player->Strings[e + 1]; //Score if (player->Strings[e].AnsiPos("team_") == 1) ListView1->Items->Item[rownumber]->SubItems->Strings[5] = player->Strings[e + 1]; //Team } //--------------------------- value = false; } }
-
Mir kommen da einige Dinge ungewöhnlich vor. Vielleicht kannst Du das mal näher erläutern.
Irgendwie sieht es für mich so aus, als ob Du die Klasse GameBrowser nur als "Zusammenfassung" verschiedener Methoden verwendest.
Normalerweise hätte ich erwartet, dass Du irgendwo mit new eine Instanz von GameBrowser erstellst und am Ende wieder freigibst.
Dein Formular TForm1 könnte beispielsweise eine Instanz dieser Klasse halten. Ich kann anhand Deines Codes nicht erkennen, dass
GameBrowser irgendeinen Zustand speichert. Am naheliegendsten wäre es doch wohl die Stringliste von GameBrowser verwalten zu lassen,
d.h. GameBrowser hat eine Member-Variable vom Typ TStringList, die auch von GameBrowser geleert und gefüllt, also allein verwaltet
wird. Vielleicht mal ein paar Code-Beispiele.// header (.h) class GameBrowser { public: GameBrowser(); ~GameBrowser(); void Clear(); int Add(AnsiString str); void GetServerInfo(int index); void SendUDPData(AnsiString ip, int port, int wasWeissIch, AnsiString irgendwas); private: TStringList* FPlayer; TStringList* serverliste; // geraten }; // Implementierung (.cpp) GameBrowser::GameBrowser() { FPlayer = new TStringList(); serverliste = new TStringList(); } GameBrowser::~GameBrowser() { delete FPlayer; delete serverliste; } void GameBrowser::Clear() { FPlayer->Clear(); } int GameBrowser::Add(AnsiString str) { return FPlayer->Add(str); } void GameBrowser::GetServerInfo(int index) { // Sowas ähnliches wie in Deinem Code-Auszug } void GameBrowser::SendUDPData(AnsiString ip, int port, int wasWeissIch, AnsiString irgendwas) { // weiter mir unbekannte Aktionen... }Ich kann allerdings nicht behaupten, dass ich Deinen Code verstehen würde.
Ein paar Dinge sind mir noch aufgefallen, die Fehler verursachen könnten:
- StrToInt() sollte in einen try/catch-Block, falls mal keine Zahlen drin stehen
- in der Methode ListView2SelectItem() der Aufruf
Form1->ListView1->Clear();Hier ist Form1 nicht nur unnötig, sondern kann auch mal ganz schnell zu einem Fehler führen. Wenn Du Dich irgendwann mal entschließen
solltest, mehrere Instanzen von TForm1 zu erstellen, löschst Du damit nicht ListView1 der aktuellen Instanz sondern immer ListView1
von Form1.- TStringList::Add() erwartet als Argument einen AnsiString. Wenn Du eine Variable vom Typ AnsiString hast, ist unnötig auf diese
nochmal c_str() aufzurufen (s. UDPStatus1DataReceived()).- Warum Du in GetServerInfo() eine lokale Variable vom Typ GameBrowser brauchst, ist mir rätselhaft. Um die Methode SendUDPData()
aufzurufen, sollte ein stinknormaler Aufruf ausreichen.Mir scheint es, als ob Du den Grundgedanken der Objektorientierung noch nicht richtig erfasst hast. Überlege Dir doch mal, in welche
Objekte Du Dein Problem sinnvollerweise aufteilen könntest und male Dir mal ein Klassengerüst auf. Oft lösen sich die Probleme von
selbst, wenn klar ist, welche Klasse wofür zuständig ist.Gruß,
Alexander
-
Danke Alexander ! ich werde mir mal am Wochenende Schritt für Schritt deine Anmerkungen durcharbeiten.
Vielen Dank für deine Mühe

Das Ergebnis werde ich dann posten
-
Ok, habe alle Funktionen und die Klasse so überarbeitet wie es deinem Sollzustand entspricht.
Habe den Fehler gefunden ! Warum sagt mir niemand das UDP Packete in zufälliger Reihenfolge gesendet werden
