Einzelnen Beitrag anzeigen

Benutzerbild von Sherlock
Sherlock

Registriert seit: 10. Jan 2006
Ort: Offenbach
3.798 Beiträge
 
Delphi 12 Athens
 
#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
Oliver
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