AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

Peinliche Frage zu generischen Listen

Ein Thema von Sherlock · begonnen am 29. Nov 2016 · letzter Beitrag vom 29. Nov 2016
Antwort Antwort
Seite 1 von 2  1 2   
Benutzerbild von Sherlock
Sherlock

Registriert seit: 10. Jan 2006
Ort: Offenbach
3.549 Beiträge
 
Delphi 10.3 Rio
 
#1

Peinliche Frage zu generischen Listen

  Alt 29. Nov 2016, 11:14
Ich sehe gerade den Wald vor lauter Bäumen nicht, und komme nicht mehr voran. Ich schildere mal was ich erreichen wollte, und dann zeige ich was ich getan habe, und was damit passiert

Ich habe viele Messwerte (es geht im Prinzip immer noch um das schnelle Zeichnen). Die wollte ich gerne in einer Liste ablegen, damit ich einfach neue Werte hinzufügen und genauso einfachen Zugriff habe. Dazu habe ich mir einen Typ für ein Listenelement deklariert und dann zunächst eine simple generische Liste basierend auf diesem Typ. Es zeigte sich dann, daß diese Liste zu einfach ist. Mir fehlte insbesondere eine etwas ausgefeiltere Add-Methode, die nur neue Elemente hinzufügt, d.h. prüft ob das einzufügende Element bereits in der Liste vorhanden ist (Erkennung über einen Timestamp). Also habe ich eine neue Klasse definiert, die die generische Liste beinhaltet und meine Implementierungen von Add, Count und einem Get drangegflanscht. Mein Problem ist jetzt, daß ich Objekte dieser Klasse offenbar nicht komplett aus dem Speicher bekomme.

Hier das wesentliche zu den Klassen:
Delphi-Quellcode:
  // Es gibt noch einen Stapel weitere Werte in dieser Klasse, die allesamt single sind,
  // damit tragen sie nicht mehr zum Problem bei, als die hier noch aufgeführten Werte
  TDevValue = class
  private
    fTimeOffset: single;
    fQUALITY1: string;
    fQUALITY2: string;
    fQUALITY3: string;
    fMQUALITY: string;
    fTime : TDateTime;
    fMOVEMENT: Boolean;
    procedure Init;
  public
    property TimeOffset: single read fTimeOffset;
    property QUALITY1: string read fQUALITY1;
    property QUALITY2: string read fQUALITY2;
    property QUALITY3: string read fQUALITY3;
    property MQUALITY: string read fMQUALITY;
    property Time : TDateTime read fTime;
    property MOVEMENT: Boolean read fMOVEMENT;
    constructor Create(aRow: string; aFS: TFormatSettings);
    destructor Destroy; override;
  end;

  TValueList = class
  private
    fLastTimeStamp: single;
    fDevValueList : TList<TDevValue>;
    fs : TFormatSettings;
    function GetItemCount: Integer;
  public
    function Add(aRow: string): Integer;
    function Get(aIndex: Integer): TDevValue;
    property Count: Integer read GetItemCount;
    constructor Create;
    destructor Destroy; override;
  end;
Hier die Implementierung. Kleiner Hinweis zum Konstruktor eines TDevValue: Es wird ein String erwartet, der eine Zeile einer csv-Datei repräsentiert.

Delphi-Quellcode:
constructor TDevValue.Create(aRow: string; aFS: TFormatSettings);
var
  myRow: TStringList;
begin
  inherited Create;
  Self.Init;
  if aRow.Length > 20 then
  begin
    myRow := TStringList.Create;
    try
      myRow.Delimiter := ';';
      myRow.StrictDelimiter := True;
      myRow.DelimitedText := aRow;

      fTimeOffset := StrToFloatDef(myRow[keyTimeOffset], 0, aFS);
      fQUALITY1 := myRow[keyQUALITY1];
      fQUALITY2 := myRow[keyQUALITY2];
      fQUALITY3 := myRow[keyQUALITY3];
      fMQUALITY := myRow[keyMQUALITY];
      fTime := UnixToDateTime(Floor(StrToFloatDef(myRow[keyTime], 0, aFS)), False);
      fMOVEMENT := myRow[keyMOVEMENT] = '1';
    finally
      myRow.Free;
    end;
  end;
end;

destructor TDevValue.Destroy;
begin
  // Der vermutlich klägliche Versuch UniCodeString Memoryleaks zu beseitigen
  fQUALITY1 := '';
  fQUALITY2 := '';
  fQUALITY3 := '';
  fMQUALITY := '';
  inherited;
end;

procedure TDevValue.Init;
begin
  fTimeOffset := -1;
  fQUALITY1 := '';
  fQUALITY2 := '';
  fQUALITY3 := '';
  fMQUALITY := '';
  fTime := NaN;
  fMOVEMENT := False;
end;

/////// Jetzt die Liste //////


function TValueList.Add(aRow: string): Integer;
var
  found : Boolean;
  i : Integer;
  myDevValue: TDevValue;
begin
  found := False;
  i := 0;
  myDevValue := TDevValue.Create(aRow, fs);
  if fDevValueList.Count > 0 then
  begin
    repeat
      if myDevValue.TimeOffset = fDevValueList[i].TimeOffset then
        found := True
      else
        Inc(i);
    until found or (i > fDevValueList.Count - 1);
  end;
  if not found then
  begin
    Result := fDevValueList.Add(myDevValue);
    if myDevValue.TimeOffset > fLastTimeStamp then
      fLastTimeStamp := myDevValue.TimeOffset;
  end
  else
  begin // Was ich nich brauche, kann gleich wieder weg
    myDevValue.Free;
    Result := i;
  end;
end;

constructor TValueList.Create;
begin
  fDevValueList := TList<TDevValue>.Create;
  // Die csv-Datei liefert numerische Werte mit Punkt als Dezimaltrenner
  fs := TFormatSettings.Create;
  fs.DecimalSeparator := '.';
  fLastTimeStamp := 0;
end;

destructor TValueList.Destroy;
begin
  // Was ist hier zu tun, um wirklich die einzelnen Listenelemente freizugeben?
  fDevValueList.DeleteRange(0, fDevValueList.Count - 1);
  fDevValueList.Free;
  inherited;
end;

function TValueList.Get(aIndex: Integer): TDevValue;
begin
  if (aIndex >= 0) and (aIndex < fDevValueList.Count) then
    Result := fDevValueList[aIndex]
  else
    Result := nil;
end;

function TValueList.GetItemCount: Integer;
begin
  Result := fDevValueList.Count;
end;
Irgendwie ist das alles trivial einfach...aber FastMM schimpft ganz dolle mit mir, daß ich praktisch keines der vielen tausend TDevValue Objekte freigegeben habe. Was habe ich falsch gemacht?


Sherlock
Geändert von Sherlock (Morgen um 16:78 Uhr) Grund: Weil ich es kann

Geändert von Sherlock (29. Nov 2016 um 11:18 Uhr)
  Mit Zitat antworten Zitat
Gruber_Hans_12345

Registriert seit: 14. Aug 2004
1.353 Beiträge
 
Delphi 2007 Professional
 
#2

AW: Peinliche Frage zu generischen Listen

  Alt 29. Nov 2016, 11:19
kenn mich mit genereischen listen nicht aus (hab die noch nicht)aber musst du da die Clear procedure der TList nicht überschreiben und die Dinger dann Freen die in der Liste sind?
Gruss Hans

2B or not 2B, that is FF
  Mit Zitat antworten Zitat
Lemmy
Online

Registriert seit: 8. Jun 2002
Ort: Berglen
2.283 Beiträge
 
Delphi 10.3 Rio
 
#3

AW: Peinliche Frage zu generischen Listen

  Alt 29. Nov 2016, 11:23
bei Fragen die dir peinlich sind, hilft es ab und zu in die Hilfe zu schauen:
http://docwiki.embarcadero.com/Libra...lections.TList

Zitat:
Die Klasse TObjectList stammt von TList ab und stellt einen automatischen Mechanismus für die Freigabe von Objekten bereit, die aus der Liste entfernt wurden.
sprich: TList besitzt keinen solchen Mechanismus und damit muss mal selber aufräumen oder TObjectlist<> verwenden
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman
Online

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
4.735 Beiträge
 
Delphi 10.1 Berlin Professional
 
#4

AW: Peinliche Frage zu generischen Listen

  Alt 29. Nov 2016, 11:25
Moin...

Ohne alles gelesen zu haben...
TList<> nach TObjectList<> ... schaust zu hier: http://docwiki.embarcadero.com/Libra...ectList.Create
OwnsObjects = True
  Mit Zitat antworten Zitat
Benutzerbild von Ritsch
Ritsch

Registriert seit: 15. Apr 2014
Ort: Wolfenbüttel
33 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#5

AW: Peinliche Frage zu generischen Listen

  Alt 29. Nov 2016, 11:26
Ich glaube bei TList musst du dich selbst darum kümmern die Objekte in der Liste freizugeben.
Also beim Destory alle Items durchgehen und diese freigeben.

Mit TObjectList kannst du die Eigenschaft "OwnsObject" setzen. Damit kümmert sich die Liste selbst darum die Items freizugeben beim Aufruf von .Free.

Zu langsam
Richard
  Mit Zitat antworten Zitat
Benutzerbild von Sherlock
Sherlock

Registriert seit: 10. Jan 2006
Ort: Offenbach
3.549 Beiträge
 
Delphi 10.3 Rio
 
#6

AW: Peinliche Frage zu generischen Listen

  Alt 29. Nov 2016, 11:35
Menno, keine rote Box. So einfach geht das...

Mache mich gleich dran. Danke!

Sherlock
Geändert von Sherlock (Morgen um 16:78 Uhr) Grund: Weil ich es kann

Geändert von Sherlock (29. Nov 2016 um 11:38 Uhr)
  Mit Zitat antworten Zitat
Aviator

Registriert seit: 3. Jun 2010
1.583 Beiträge
 
Delphi 10.3 Rio
 
#7

AW: Peinliche Frage zu generischen Listen

  Alt 29. Nov 2016, 11:47
Es wurde ja schon mehrfach erwähnt. Die TList Klasse gibt die Elemente die sie beinhaltet nicht wieder automatisch frei. Siehe auch TList.Destroy (die Anmerkung). Deshalb wäre es vielleicht sinnvoll, auf eine TObjectList umzusteigen und diese mit OwnsObjects = True zu erzeugen.

Alternativ müsstest du im Destructor deiner TValueList Klasse durch alle Elemente iterieren und diese dann freigeben.

Übrigens:

Delphi-Quellcode:
  if fDevValueList.Count > 0 then
  begin
    repeat
      if myDevValue.TimeOffset = fDevValueList[i].TimeOffset then
        found := True
      else
        Inc(i);
    until found or (i > fDevValueList.Count - 1);
  end;
Kann man auch so schreiben:

Delphi-Quellcode:
  if fDevValueList.Count > 0 then
  begin
    repeat
      if myDevValue.TimeOffset = fDevValueList[i].TimeOffset then
        found := True
      else
        Inc(i);
    until found or (i = fDevValueList.Count); // <-------- ÄNDERUNG HIER
  end;
Mir stellt sich jetzt nur noch die Frage, wieso du überhaupt noch die Liste durchlaufen musst. Du setzt dir doch schon in fLastTimeStamp den zuletzt hinzugefügten TimeStamp. Reicht es dann nicht einfach zu überprüfen, ob der neue TimeStamp größer/neuer ist als der zuletzt hinzugefügte?
  Mit Zitat antworten Zitat
Benutzerbild von Sherlock
Sherlock

Registriert seit: 10. Jan 2006
Ort: Offenbach
3.549 Beiträge
 
Delphi 10.3 Rio
 
#8

AW: Peinliche Frage zu generischen Listen

  Alt 29. Nov 2016, 11:48
Ja, schon sind die Objekte alle freigegeben worden, und ich kann mich dem Freigeben der Bitmaps widmen.... Danke Euch allen!
Und Aviator, danke für die Optimierung...ich stand wohl sehr weit neben mir. Im Nachbarort, sozusagen

Sherlock
Geändert von Sherlock (Morgen um 16:78 Uhr) Grund: Weil ich es kann
  Mit Zitat antworten Zitat
Aviator

Registriert seit: 3. Jun 2010
1.583 Beiträge
 
Delphi 10.3 Rio
 
#9

AW: Peinliche Frage zu generischen Listen

  Alt 29. Nov 2016, 12:05
Und Aviator, danke für die Optimierung...ich stand wohl sehr weit neben mir. Im Nachbarort, sozusagen
Keine Ursache.

Hast du denn noch meine zusätzliche Anmerkung gelesen? Kannst du dich auf den TimeStamp verlassen den du dir zwischenspeicherst?
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
38.276 Beiträge
 
Delphi 10.4 Sydney
 
#10

AW: Peinliche Frage zu generischen Listen

  Alt 29. Nov 2016, 12:14
Das IF könnte man och noch wegoptimieren, wenn man die Schleife zuerst prüft.
Delphi-Quellcode:
    while i < fDevValueList.Count do begin
      //if myDevValue.TimeOffset = fDevValueList[i].TimeOffset then begin
      if SameValue(myDevValue.TimeOffset, fDevValueList[i].TimeOffset) then begin
        found := True;
        Break;
      end;
      Inc(i);
    end;
Aber wichtiger wären die Float-Vergleiche, denn die Floats haben ja dieses winzige Rundungsproblemchen.
Delphi-Referenz durchsuchenSameValue
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
Delphi-Tage 2005-2014
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2   

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +2. Es ist jetzt 10:36 Uhr.
Powered by vBulletin® Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf