Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi array of X - Suche nach Element (https://www.delphipraxis.net/143954-array-x-suche-nach-element.html)

peter001 26. Nov 2009 18:56


array of X - Suche nach Element
 
Hallo!

Eigentlich ein Anfängerproblem, aber ich habe scheinbar irgend einen Denkfehler.

Ich habe mir eine Art cache gebaut, Cache ist ein Objekt mit Methoden "isCached(name) -> boolean", "addToCache(CacheEntry)" und "getCached(pos) -> CacheEntry".

Als Attribut hat diese Klasse ein Array of TCacheEntry, welches im Constructor auf die Länge 0 gesetzt wird (dynamisches array).

Hier mal der Code:

Delphi-Quellcode:
unit QCache;

interface

uses
  ..., QCacheEntry;

type
  TQueryCache = class(TObject)
    entries: array of TQueryCacheEntry;

    constructor Create;
    destructor Destroy;

    function isCached(name: string; var pos:integer): boolean;
    function getCached(pos: integer): TQueryCacheEntry;
    procedure addEntryToCache(Charinfo: TQueryCacheEntry);
    function getNumEntries: integer;
  end;

var
  QueryCache: TQueryCache;

implementation

constructor TQueryCache.Create;
begin
  SetLength(entries,0);
end;

destructor TQueryCache.Destroy;
begin
  //
end;

function TQueryCache.getNumEntries: integer;
begin
  Result := Length(entries);
end;

function TQueryCache.getCached(pos: integer): TQueryCacheEntry;
begin
  if entries[pos] <> nil then
  Result := entries[pos];
end;

function TQueryCache.isCached(name:string; var pos:integer):boolean;
var
  i: integer;
begin
  Result := false;
  pos := 0;
  try
    if Length(entries) > 0 then
    begin
      for i := 0 to Length(entries)-1 do
      begin
        if entries[i].option1 = name then
        begin
          Result := true;
          pos := i;
        end;
      end;
    end;
  except
    Result := false;
  end;
end;

procedure TQueryCache.addEntryToCache(Charinfo: TQueryCacheEntry);
begin
  SetLength(entries,Length(entries)+1);
  entries[Length(entries)-1] := Charinfo;
  Charinfo.Free;
end;

end.
und hier die TQueryCacheEntry:
Delphi-Quellcode:
unit QCacheEntry;

interface

type
  TQueryCacheEntry = class(TObject)
    option1: string;
    option2: string;
    option3: string;
    option4: string;
    option5: string;
    option6: string;

constructor Create;
end;

implementation

constructor TQueryCacheEntry.Create;
begin
  inherited Create;
  option1:= '';
  option2:= '';
  option3:= '';
  option4:= '';
  option5:= '';
  option6:= '';
end;

end.

Problem ist nun dieser Abschnitt, wo ich eine Funktion aufrufe:

Delphi-Quellcode:
procedure TForm1.testName(name:string);
var
  ...
  qpos: integer;
  Charinfo: TQueryCacheEntry;
begin
  qpos := 0;

  if Cache.isCached(name, qpos) = true then // <- Fehler kommt in dieser Zeile
  begin
    ListBox1.Items.Add('Found Object in cache: ' + name + ' in Position: ' + IntToStr(qpos) + ' and total cache size: ' + IntToStr(Cache.getNumEntries));
    Charinfo := Cache.getCached(qpos);
  end else
  ...
Ich bekomme also einen Namen und prüfe, ob dieser Name irgendwo im Cache auftaucht.
Als Fehler bekomme ich die Meldung "...exe raised an exception. Error in Reading of Adress ..." Also für mich sehr nichtssagend.
Stehen bleibt er bei der oben markierten Zeile.
Problem scheint also diese Methode "isCached" zu sein, die das dynamische Array mit den Cache Einträgen durchläuft, nach einer Übereinstimmung sucht und dessen Position zurückgibt.

Delphi-Quellcode:
function TQueryCache.isCached(name:string; var pos:integer):boolean;
var
  i: integer;
begin
  Result := false;
  pos := 0;
  try
    if Length(entries) > 0 then
    begin
      for i := 0 to Length(entries)-1 do
      begin
        if entries[i].option1 = name then
        begin
          Result := true;
          pos := i;
        end;
      end;
    end;
  except
    Result := false;
  end;
end;
Was ist da verkehrt?

Ich danke für jede Antwort, falls ihr mehr Infos braucht, sagt bescheid.

Apollonius 26. Nov 2009 19:03

Re: array of X - Suche nach Element
 
In addEntryToCache gibst du das übergebene Objekt frei. Danach steht im Array nur noch Müll.

Klaus01 26. Nov 2009 19:10

Re: array of X - Suche nach Element
 
Delphi-Quellcode:
procedure TQueryCache.addEntryToCache(Charinfo: TQueryCacheEntry);
begin
  SetLength(entries,Length(entries)+1);
  entries[Length(entries)-1] := Charinfo;
  Charinfo.Free;
end;
Hallo,

wie Apollonius scho beschrieben hat gibts du die Instanz wieder frei.
Da Du nur die Addresse der Instanz Deinem Array übergeben hast ist
auch das Element im Array nicht mehr existent.

Vielleicht ist es besser in der addEntryToCache Methode
alle Daten von CharInfo zu kopieren.
Also ein neues Element im Array erzeugen und dann den Inhalt von
CharInfo in das neue Element kopieren.

Grüße
Klaus

peter001 26. Nov 2009 19:21

Re: array of X - Suche nach Element
 
Super danke euch!

Genau sowas in der Art hatte ich mir gedacht :D

himitsu 26. Nov 2009 19:24

Re: array of X - Suche nach Element
 
warum das globale var QueryCache: TQueryCache; ?

die Konstruktoren kannst du dir sparen
- dynamische Array und String sind per Standard eh leer

leere Destruktoren/Funktionen sind ebenfalls sinnlos

getCached liefert einen undefinierten Wert, wenn nichts im Cache ist

if Length(entries) > 0 then in isCached bringt auch nichts, denn dieses ist praktisch in der Forschleife schon vorhanden.

Try-Except ... eine dort auftretende Exception sollte man nicht einfach unter den Tisch kehren, denn dieses würde auf eine defekte Datenstruktur hinweisen und sowas dürfte eh nie auftreten

Vergleiche mit =true macht man nicht :!:
(es sei denn man muß GENAU auf True(1) vergleichen)

Delphi-Quellcode:
unit QCache;

interface

uses
  ..., QCacheEntry;

type
  TQueryCache = class(TObject)
  private
    entries: array of TQueryCacheEntry;
  public
    function isCached(name: string; var pos:integer): boolean;
    function getCached(pos: integer): TQueryCacheEntry;
    procedure addEntryToCache(Charinfo: TQueryCacheEntry);
    function getNumEntries: integer;
  end;

implementation

function TQueryCache.getNumEntries: integer;
begin
  Result := Length(entries);
end;

function TQueryCache.getCached(pos: integer): TQueryCacheEntry;
begin
  //if Assigned(entries[pos]) then
  //  Result := entries[pos]
  //else
  //  Result := nil;

  // gekürzt kommt das bei raus und nebenbei wird nun nur noch einmal gesucht :)
  Result := entries[pos];
end;

function TQueryCache.isCached(name:string; var pos:integer):boolean;
var
  i: integer;
begin
  Result := false;
  for i := 0 to Length(entries)-1 do
    if entries[i].option1 = name then
    begin
      Result := true;
      pos := i;
      break; // wenn gefunden, dann braucht man nicht weitersuchen
    end;
end;

procedure TQueryCache.addEntryToCache(Charinfo: TQueryCacheEntry);
begin
  SetLength(entries,Length(entries)+1);
  entries[High(entries)] := Charinfo;
end;

end.
Delphi-Quellcode:
unit QCacheEntry;

interface

type
  TQueryCacheEntry = class(TObject)
    option1: string;
    option2: string;
    option3: string;
    option4: string;
    option5: string;
    option6: string;
  end;

implementation

end.
Delphi-Quellcode:
procedure TForm1.testName(name:string);
var
  ...
  qpos: integer;
  Charinfo: TQueryCacheEntry;
begin
  qpos := 0;

  if Cache.isCached(name, qpos) then
  begin
    ListBox1.Items.Add('Found Object in cache: ' + name + ' in Position: ' + IntToStr(qpos) + ' and total cache size: ' + IntToStr(Cache.getNumEntries));
    Charinfo := Cache.getCached(qpos);
  end else
  ...

Christian Seehase 26. Nov 2009 21:11

Re: array of X - Suche nach Element
 
Moin Peter,

Zitat:

Zitat von himitsu
Vergleiche mit =true macht man nicht :!:
(es sei denn man muß GENAU auf True(1) vergleichen)

was analog auch für das Prüfen auf false gilt.
Dann sollte man nur auf "if not Boolscher-Ausdruck then" prüfen.


Du könntest übrigens auf Deine eigene Listenimplementierung verzichten, wenn Du Deine Liste nicht von TObject sondern von TObjectList (zu finden in der Unit contnrs) ableitest.
Da die Cache-Entries Objekte sind, bietet sich das, meiner Ansicht nach, an.
Das dürfte Deine Liste vereinfachen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:16 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz