TList - Fehler beim Auslesen soeben gespeicherter Objekte

Für allgemeine Fragen zur Programmierung, welche nicht! direkt mit Lazarus zu tun haben.
Erhard
Beiträge: 7
Registriert: Mo 10. Aug 2020, 23:06

TList - Fehler beim Auslesen soeben gespeicherter Objekte

Beitrag von Erhard »

Hallo zusammen,

vor langer Zeit habe ich viel mit Turbo-Pascal und Delphi gearbeitet, mache jetzt meine ersten Schritte mit FreePascal und stolperte geradewegs in eine Falle. Folgendes Verhalten kann ich mir nicht erklären:

Eine Textdatei wird zeilenweise ausgelesen und in jeder Zeile wird ein Objekt oMsg mit zwei Strings versorgt. Dies wird mittels Logger 'D' gelogged.
Unter bestimmten Bedingungen wird das so gefüllte Objekt in die Liste geschrieben (Add) und nochmals gelogged ('W'). Dann wird dieses zuletzt hinzugefügte Objekt wieder ausgelesen und angezeigt - sieht auch gut aus, Logger 'I':

Code: Alles auswählen

	
	TRY
     	Assign(oFile, sPath);
        Reset(oFile);
        REPEAT
			ReadLn(oFile, sLine);
			oMsg.key := StrUtils.ExtractWord(1, sLine, oDelims);
			oMsg.text := StrUtils.ExtractWord(2, sLine, oDelims);
Logger.GetInstance.PutLog('D', IntToStr(iIndex), oMsg.key + ' - ' + oMsg.text);
			IF (NOT StrUtils.AnsiStartsStr('[', oMsg.key)) THEN BEGIN
Logger.GetInstance.PutLog('W', IntToStr(iIndex), oMsg.key + ' - ' + oMsg.text);
				oListe.Add(oMsg);
				oMsg := oListe[iIndex];
Logger.GetInstance.PutLog('I', IntToStr(iIndex), oMsg.key + ' - ' + oMsg.text);
            inc(iIndex);
			END;
		UNTIL EOF(oFile);
		FINALLY
			iNum := oListe.Count;
			Close(oFile);
	 END;                  
Das Log sieht korrekt aus:

Code: Alles auswählen

11.08.2020 20:25:02 - DEBUG: 8 EDIT		-  Bearbeiten
11.08.2020 20:25:02 - WARNING: 8 EDIT		-  Bearbeiten
11.08.2020 20:25:02 - INFO: 8 EDIT		-  Bearbeiten
Beim Auslesen später wird jedoch immer nur das zuletzt hinzu gefügte Objekt angezeigt, egal welchen Index man angibt. Gleich im Anschluss an obigen Code habe ich folgende Zeilen eingebaut:

Code: Alles auswählen

FOR iIndex := 0 TO iNum DO BEGIN
   oMsg := oListe[iIndex];
   IF (oMsg <> nil) THEN BEGIN
    Logger.GetInstance.PutLog('E', IntToStr(iIndex), oMsg.key + ' - ' + oMsg.text);
   END;
END;    
Das Ergebnis ist jedoch nicht - wie erwartet - eine Anzeige aller Objekte sondern 32 mal das letzte:

Code: Alles auswählen

...
11.08.2020 20:25:02 - ERROR: 6 ABOUT_PROGRAM            -  über das Programm
11.08.2020 20:25:02 - ERROR: 7 ABOUT_PROGRAM            -  über das Programm
11.08.2020 20:25:02 - ERROR: 8 ABOUT_PROGRAM            -  über das Programm
...
Sicher habe ich einen ganz dummen Fehler gemacht, obwohl ich mich am Wiki orientiert habe und bitte schon mal gleich um Entschuldigung.
Ich sitze bereits seit Tagen vor dem Problem, komme aber nicht dahinter.

Vielen Dank im voraus!

Mathias
Beiträge: 6162
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: TList - Fehler beim Auslesen soeben gespeicherter Objekte

Beitrag von Mathias »

Versuche mal

Code: Alles auswählen

FOR iIndex := 0 TO iNum - 1 DO BEGIN
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: TList - Fehler beim Auslesen soeben gespeicherter Objekte

Beitrag von wp_xyz »

Was ist denn dieser Logger? Und was macht das PutLog genau? Und was ist oListe? Die TList vom titel? Leute, lasst uns halt nicht so viel raten!
Zuletzt geändert von wp_xyz am Di 11. Aug 2020, 23:52, insgesamt 2-mal geändert.

Erhard
Beiträge: 7
Registriert: Mo 10. Aug 2020, 23:06

Re: TList - Fehler beim Auslesen soeben gespeicherter Objekte

Beitrag von Erhard »

Danke, aber das habe ich natürlich.
Aendert aber nichts.
Es funktioniert auch nicht mit einzelnen Elementen wie "oListe[7]" .

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: TList - Fehler beim Auslesen soeben gespeicherter Objekte

Beitrag von theo »

Ich glaube der Haken liegt in dem Code, den du nicht zeigst.
Z.B. wenn du nur ein oMsg (was ist das genau?) createst, kann das auch nur einen Wert halten, nämlich den letzten.
Aber das sieht man in den Codefetzen nicht.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: TList - Fehler beim Auslesen soeben gespeicherter Objekte

Beitrag von af0815 »

Wenn so ein Konstrukt nicht geht, dann Teste mal eine vereinfachte Form davon. Weil so wie du das hier vorstellst, ohne Typen und Objektbeschreibung, kannst du und wir nichts sehen. Für mich hat der Logger und deine oListe nichts gemein. Da sieht man absolut nicht wie die Daten in die oListe kommen.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: TList - Fehler beim Auslesen soeben gespeicherter Objekte

Beitrag von Socke »

af0815 hat geschrieben:
Mi 12. Aug 2020, 09:11
Da sieht man absolut nicht wie die Daten in die oListe kommen.
Da ist ein oListe.Add(oMsg); - das geht in der Code-Formattierung/Einrückung ein wenig unter.
Vermutlich musst du das Objekt oMsg in jedem Schleifendurchlauf neu erzeugen:

Code: Alles auswählen

oMsg := TMessageClass.Create; // welche Klasse hier richtig ist, wirst du selber wissen.
oMsg.key := StrUtils.ExtractWord(1, sLine, oDelims);
oMsg.text := StrUtils.ExtractWord(2, sLine, oDelims);
Andernfalls hast du nur ein Objekt, dass immer den Inhalt des letzten Schleifendurchlaufs enthält. In der Liste wird dann an jeder Position das selbe Objekt referenziert.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: TList - Fehler beim Auslesen soeben gespeicherter Objekte

Beitrag von theo »

@Socke: Ziemlich genau das, hatte ich gestern Abend schon geschrieben. :wink:

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: TList - Fehler beim Auslesen soeben gespeicherter Objekte

Beitrag von Socke »

theo hat geschrieben:
Mi 12. Aug 2020, 10:20
@Socke: Ziemlich genau das, hatte ich gestern Abend schon geschrieben. :wink:
Ich hab's doch nur visualisieren wollen :oops:
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Erhard
Beiträge: 7
Registriert: Mo 10. Aug 2020, 23:06

Re: TList - Fehler beim Auslesen soeben gespeicherter Objekte

Beitrag von Erhard »

Hallo zusammen,

leider komme ich immer nur abends dazu, in's Forum zu schauen - daher bitte das delay zu entschuldigen.

Das hier war's: "Vermutlich musst du das Objekt oMsg in jedem Schleifendurchlauf neu erzeugen".

Jetzt funktioniert's, auch wenn mir schleierhaft, warum ich den Inhalt eines existierenden Objektes nicht durch neue Daten überschreiben kann. Etwas anderes passiert doch beim ersten mal nach dem create auch nicht.

Wie dem auch sei - vielen Dank allen!
Erhard

PascalDragon
Beiträge: 825
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: TList - Fehler beim Auslesen soeben gespeicherter Objekte

Beitrag von PascalDragon »

Erhard hat geschrieben:
Mi 12. Aug 2020, 20:59
Jetzt funktioniert's, auch wenn mir schleierhaft, warum ich den Inhalt eines existierenden Objektes nicht durch neue Daten überschreiben kann. Etwas anderes passiert doch beim ersten mal nach dem create auch nicht.
Delphi-style Objekte (im Gegensatz zu TP-style Objeksten) sind immer implizite Zeiger. Beim Hinzufügen in die Liste hast du den Zeiger auf das Objekt hinzugefügt und dann das bereits hinzugefügte Objekt geändert und den gleichen Zeiger erneut hinzugefügt. Wenn du eine neue Objektinstanz mittels Create erzeugst, dann enthält die Objektvariable auch einen neuen Zeigerwert. Bei Records hast du im Allgemeinen eine Kopie des Objekts, es sei denn du nimmst explizit Zeiger her.

In dem Sinne noch ein weiterer Hinweis: du solltest natürlich die Objekte in deiner Liste am Ende auch wieder mit Free freigeben, sonst hast du ein Speicherleck. Diese kannst du finden, wenn du die Option -gh in den Compilereinstellungen aktivierst, Dann erscheint am Ende ein Dialog (oder mehrere), der dich über Speicherlecks informiert. ;)
FPC Compiler Entwickler

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: TList - Fehler beim Auslesen soeben gespeicherter Objekte

Beitrag von photor »

Erhard hat geschrieben:
Mi 12. Aug 2020, 20:59
Das hier war's: "Vermutlich musst du das Objekt oMsg in jedem Schleifendurchlauf neu erzeugen".

Jetzt funktioniert's, auch wenn mir schleierhaft, warum ich den Inhalt eines existierenden Objektes nicht durch neue Daten überschreiben kann. Etwas anderes passiert doch beim ersten mal nach dem create auch nicht.
Anfangs selbst of genug reingefallen.

Durch das Create wird das (= ein!) Objekt erzeugt, d.h. die Struktur wird im angelegt. Die befüllst du jetzt, um sie in die TList zu hängen. Das "in die TListe hängen" heißt aber, dass da nur ein Zeiger auf dieses Stück Speicher in deine TList gepackt wird. Wenn du die Daten abrufst, wird über diesen Zeiger auf die Daten (= das eine Stück Speicher, dass du anfangst angelegt hattest) zugegriffen.

Wenn du in der nächsten Runde jetzt kein(!) neues Create aufrufst, sondern das Objekt nochmal befüllst, überschreibst du deine ersten Daten - der Zeiger zeigt immer noch auf den zuerst angelegten Speicherbereich. Wenn du den jetzt nochmal in deine TList packst, sind da nur zwei gleiche Zeiger (und damit 2 mal das selbe Objekt) drin.

Erst wenn du bei jeder Runde einmal Create aufrufst, wird jedes mal ein neues Objekt (neuer, frischer Speicher) angelegt, den du befüllst und dessen Zeiger du wieder in die TList hängst.

Und nicht nach dem letzten angehängten Element meinen, die Struktur freigeben zu wollen; dann fehlt das letzte Element (bzw. enthält Schrott). Aufräumen musst erst dann, wenn die TList wieder aufgelöst wird.

Eigene Erfahrung, wie gesagt.

Caio,
Photor

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: TList - Fehler beim Auslesen soeben gespeicherter Objekte

Beitrag von theo »

Oder TObjectList https://www.freepascal.org/docs-html/fc ... tlist.html verwenden, die hilft beim Aufräumen

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: TList - Fehler beim Auslesen soeben gespeicherter Objekte

Beitrag von photor »

Stimmt! Hatte ich vergessen. Bin ich auch erst letztens drauf gestoßen worden.

Ciao,
Photor

Erhard
Beiträge: 7
Registriert: Mo 10. Aug 2020, 23:06

Re: TList - Fehler beim Auslesen soeben gespeicherter Objekte

Beitrag von Erhard »

Vielen Dank für die zusätzlichen Erläuterungen!
So wird's verständlich.

Grüße
Erhard

Antworten