AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

array of const für spätere Verwendung speichern

Ein Thema von BigAl · begonnen am 31. Jan 2016 · letzter Beitrag vom 1. Feb 2016
Antwort Antwort
BigAl

Registriert seit: 6. Sep 2008
Ort: Kehl
504 Beiträge
 
Delphi 12 Athens
 
#1

array of const für spätere Verwendung speichern

  Alt 31. Jan 2016, 18:31
Hallo zusammen,

ich kämpfe hier gerade mit einem Problem. Ich habe eine Methode geschrieben, welche als Parameter "array of const" beinhaltet. Dieses "array of const" soll zu einem späteren Zeitpunkt an die "Format"-Funkion übergeben werden. "array of const" ist ja bekanntermaßen ein "array of TVarRec". Also habe ich das auch so deklariert (Strukturen und Code für bessere Übersichtlichkeit gekürzt):

Delphi-Quellcode:
  PRec = ^TRec;
  TRec = record
    Params: array of TVarRec;
  end;
In meiner Methode werden die Werte dann mit folgendem Code zwischengespeichert:

Delphi-Quellcode:
procedure Something(const Args: array of const);
var
  RecPtr: PRec;
begin
  New(RecPtr);
  SetLength(RecPtr^.Params, Length(Args));
  for I := Low(Args) to High(Args) do
    RecPtr^.Params[I] := Args[I];
end;
Soweit so gut. Der generierte Record wird einer Thread-Liste abgelegt und dann von einer anderen Thread verarbeitet. Das funktioniert auch alles bestens, solange ich Strings oder Konstante Werte in "Args" übergebe. Übergebe ich aber z.B. eine numerische Variable, so ist diese nur verfügbar, solange ich in der Methode "Something" bin. Beim Verlassen der Methode wird diese finalisiert und löst dann natürlich eine Exception aus, sobald auf diese zugegriffen wird. Ich habe das getestet indem ich in der Methode geblieben bin, bis die Thread die Parameter verarbeitet hatte...

Zum weiteren Verständnis: Die Thread holt die Records nacheinander vom Puffer (TThreadList) und verarbeitet diese asynchron zum aufrufenden Programm. Leider können die Args erst dort verarbeitet werden, da die endgültigen Formatstrings erst in der Thread verfügbar sind...

Mir fällt leider im Moment keine elegante Lösung ein. Irgendwie müsste ich mich da manuell um "Initialize" und "Finalize" kümmern. Hat jemand von euch eine Idee? Ich hoffe das Problem ist einigermaßen verständlich geschildert und ich habe mich beim "Pseudo"-Code nicht zu sehr vertippt .

PS: Eine Lösung wäre bei bestimmten Typen (z.B. VExtended) die als Pointer gespeichert werden diese mit New(RecPtr^.Params[I].VExtended) dynamisch zu allokieren und den Wert mit RecPtr^.Params[I].VExtended^ := Args[I].VExtended^ zu übernehmen. Später müsste dann dieser mit Dispose(RecPtr^.Params[I].VExtended) dann wieder freiegeben werden. Ist aber sehr umständlich und man müsste die richtigen Typen ermitteln und das bei allen (auch zukünftigen) Typen korrekt durchführen. Ist nicht sehr elegant.

Freue mich über alle Antworten!

Alex
Man sollte nie so viel zu tun haben, dass man zum Nachdenken keine Zeit mehr hat. (G.C. Lichtenberg)

Geändert von BigAl (31. Jan 2016 um 19:34 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#2

AW: array of const für spätere Verwendung speichern

  Alt 31. Jan 2016, 19:42
Kannst du einen minimalen Testfall bereitstellen?
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#3

AW: array of const für spätere Verwendung speichern

  Alt 1. Feb 2016, 10:47
Was sind "nummerische Werte"?
Delphi-Quellcode:
  TVarRec = record { do not pack this record; it is compiler-generated }
    case Integer of
      0: (case Byte of
            vtInteger: (VInteger: Integer);
            vtExtended: (VExtended: PExtended);
            vtString: (VString: PShortString);
            vtAnsiString: (VAnsiString: Pointer);
            vtCurrency: (VCurrency: PCurrency);
            vtVariant: (VVariant: PVariant);
            vtWideString: (VWideString: Pointer);
            vtInt64: (VInt64: PInt64);
            vtUnicodeString: (VUnicodeString: Pointer);
Alles größer als Integer wird per Pointer referenziert und lebt nur so lange, wie es der aufrufende Code bereitstellt.
Strings sind referenzgezählt und in diesem Array wird die Referenz nicht mitgezählt (CONST) ... geht der Referenzzähler auf 0, so ist der String weg.

Fazit:
Du mußt selber einen Speicherplatz bereitstellen und die Inhalte umkopieren, wenn sie nicht im aktuellen Programmpfad behandelt werden.

z.B. ein paar Array of AnsiString/UnicodeString/Int64/Extended/Variant, auf deren Speicher dann deine TVarRec zeigen.
(alternativ nur Array of Variant und alles nach Variant konvertieren)

New/Dispose wären auch möglich, aber so mußt du dich nicht um das (interne) Speichermanagement kümmern.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu ( 1. Feb 2016 um 10:53 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#4

AW: array of const für spätere Verwendung speichern

  Alt 1. Feb 2016, 13:31
Ich würde das mal mit TValue versuchen. Der löst in FromVarRec die Referenzen auf die Pointer auf. Die Zuweisung kann in dem Fall sogar wegen Implicit so bleiben. Lediglich bei der Auswertung muss man dann halt was machen (z.B. über AsVarRec ).

Delphi-Quellcode:
 PRec = ^TRec;
  TRec = record
    Params: array of TValue;
  end;
Delphi-Quellcode:
procedure Something(const Args: array of const);
var
  RecPtr: PRec;
begin
  New(RecPtr);
  SetLength(RecPtr^.Params, Length(Args));
  for I := Low(Args) to High(Args) do
    RecPtr^.Params[I] := Args[I];
end;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#5

AW: array of const für spätere Verwendung speichern

  Alt 1. Feb 2016, 14:59
TValue: Dieses Array kann man aber nicht an ein array of const übergeben?

Delphi-Quellcode:
procedure Something(const Args: array of const);
var
  RecPtr: PRec;
begin
  New(RecPtr);
  SetLength(RecPtr.Params, Length(Args));
  for I := Low(Args) to High(Args) do
    RecPtr.Params[I] := Args[I];
  //
  Format('', RecPtr.Params);
  Dispose(RecPtr);
end;
PS: Bei Record-Pointer kann man die Dereferenzierung weg lassen, wenn man auf Felder/Property/Funktionen zugreift, da Delphi das impliziet macht. Halt wie bei den Objekten, nur dass dort die explizite Angabe nicht erlaubt ist.
Aber so lässt sich der Code später mal problemloser auf schöne Datenobjekte umstellen.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu ( 1. Feb 2016 um 15:04 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#6

AW: array of const für spätere Verwendung speichern

  Alt 1. Feb 2016, 15:34
TValue: Dieses Array kann man aber nicht an ein array of const übergeben?
Nicht direkt, aber über eine Schleife lässt sich natürlich einfach wieder ein array of TVarRec aufbauen:

Delphi-Quellcode:
type
  TRec = record
  private
    function GetAsVarRecs: TArray<TVarRec>;
  public
    Params: array of TValue;
    constructor Create(const AParams: array of const);
    property AsVarRecs: TArray<TVarRec> read GetAsVarRecs;
  end;

constructor TRec.Create(const AParams: array of const);
var
  I: Integer;
begin
  SetLength(Params, Length(AParams));
  for I := Low(AParams) to High(AParams) do begin
    Params[I] := AParams[I];
  end;
end;

function TRec.GetAsVarRecs: TArray<TVarRec>;
var
  I: Integer;
begin
  SetLength(result, Length(Params));
  for I := Low(Params) to High(Params) do begin
    result[I] := Params[I].AsVarRec;
  end;
end;

procedure Test(const Fmt: string; const Args: array of const);
var
  rec: TRec;
  S: string;
begin
  rec := TRec.Create(Args);
  S := Format(Fmt, rec.AsVarRecs);
  Assert(S = Format(Fmt, Args));
end;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Antwort Antwort


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 +1. Es ist jetzt 06:21 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