![]() |
Custom Record Freigabe verkettete liste
Ich habe versucht eine datenstruktur wie folgt aufzubauen, (records sind ja managed?)
Delphi-Quellcode:
Da records keinen Destructor einführen habe ich die
Pnum = ^Tlargenum;
Tlargenum= Record Private FLength, Fchunkcount: Word; FNext: pmyrec; _ispositive: Boolean; Const _Chunkdigits = 10; Type Tdigit = 0 .. 9; Var FDigits: Array [0 .. _Chunkdigits - 1] Of Tdigit; Private Class Procedure Clear(Var A: Tlargenum); Static; public Constructor Create(Avalue: Pchar); Procedure Free; end
Delphi-Quellcode:
clear, welche rekursiv alles löschen soll:
class procedure
Delphi-Quellcode:
soweit sogut:Constructor Tlargenum.Create(Avalue: Pchar); Var Digitindex: Integer; Begin Inherited; If Assigned(Avalue) Then Begin If Avalue = '' Then Create('0') Else Begin Fnext := Nil; // Clear; FLength := 0; // System.Length(Avalue); Fchunkdigitcount := 0; Digitindex := 0; // get sign _ispositive := Avalue^ <> '-'; If Not _ispositive Then Dec(Flength); While Not(Avalue^ In ['0' .. '9']) And (Avalue <> Nil) Do Inc(Avalue); While Avalue^ <> #0 Do Begin FDigits[Digitindex] := Strtoint(Avalue^); Inc(Avalue); Inc(Digitindex); Inc(Fchunkdigitcount); Inc(Flength); If Digitindex = _Chunkdigits Then Begin New(Fnext); Fnext^ := Tlargenum.Create(Avalue); Flength := Flength + Fnext^.Flength; Break; End; End; End; End; End; Procedure Tlargenum.Free; Begin Clear(Self); End; Class Procedure Tlargenum.Clear(Var A: Tlargenum); Var Temp: Pnum; Adigit: Pbyte; Begin A._ispositive := False; A.FLength := 0; A.Fchunkdigitcount := 0; Fillchar(A.Fdigits, System.Length(A.Fdigits), 0); While Assigned(A.Fnext) Do Begin Temp := A.Fnext; A.Fnext := A.Fnext^.FNext; Dispose(Temp); End; // Fmath := Nil; End; nun führe ich class operators ein:
Delphi-Quellcode:
Class Operator Implicit(A: Tlargenum): String; Overload; // OK
Class Operator Explicit(A: Tlargenum): Integer; Overload; // OK Class Operator Explicit(A: Tlargenum): Byte; Overload; // OK // Class Operator Explicit(A: String): Tlargenum; Overload; Class Operator Implicit(A: Uint64): Tlargenum; Overload; Class Operator Implicit(A: Int64): Tlargenum; Overload; Class Operator Implicit(A: String): Tlargenum; Overload;
Delphi-Quellcode:
Die jeweiligen Conversions werden korrekt durchgeführt, aber zb. implicit conversions wie
Class Operator Tlargenum.Implicit(A: String): Tlargenum;
// Var // Returnrec: Tlargenum; Begin Result := Tlargenum.Create(Pchar(A)); // Result := Returnrec; End; Class Operator Tlargenum.Implicit(A: Tlargenum): String; Var I: Byte; Begin Result := ''; I := 0; While I < A.Fchunkdigitcount Do Begin Result := Result + Inttostr(A.FDigits[I]); Inc(I); End; If Assigned(A.FNext) Then Result := Result + A.Fnext^; End; Class Operator Tlargenum.Explicit(A: Tlargenum): Integer; Begin // ok: Var Temp: Tlargenum; Temp := High(Integer); Try If A < Temp Then Result := Strtoint(A) Else Raise Eoverflow.Create('Cant be converted into integer type'); // error Except On E: Exception Do Showmessage(E.Message) End; Temp.Free; { If A > High(integer) Then Raise Exception.Create('Number cannot be converted into byte'); Result := Strtoint(A); } End; Class Operator Tlargenum.Explicit(A: Tlargenum): Byte; Begin Var Temp: Tlargenum; Temp := High(Byte); If A > Temp Then Raise Exception.Create('Number cannot be converted into byte'); Result := Strtoint(A); Temp.Free; End; Class Operator Tlargenum.Implicit(A: Uint64): Tlargenum; Var Temp: String; Begin Temp := UInttostr(A); Result := Temp; // Result.FLength := Length(Temp); // Result._ispositive := True; End; Class Operator Tlargenum.Implicit(A: Int64): Tlargenum; Begin Result := Uint64(Abs(A)); Result._ispositive := A >= 0; End;
Delphi-Quellcode:
führen zu leaks, da die impliziten records nie freigegeben werden.
Assert(X > '3000000000000000');//x is vom typ tlargenum, der string wird implizit umgewandelt
Assert(X >= '3000000000000000'); Wie kann ich den speicher denn hier wieder sauber freigeben? Danke |
AW: Custom Record Freigabe verkettete liste
Zitat:
Mit dem Pointer auf den nächsten Record weis der Delphi-Compiler nichts anzufangen. Warum speicherst du deine Ziffern in einer verketten Liste von Records? Ein einfacher String oder ein dynamisches Array können fast beliebige Anzahl von Ziffern in einem Record aufnehmen. Verkettete Listen sind eher etwas für Lernübungen mit Pointern. Im Normalfall sind Array bzw. TList schneller und einfacher zu benutzen. |
AW: Custom Record Freigabe verkettete liste
Danke für deine Rückmeldung.:)
Anstatt des (noch) nicht verfügbaren destructors habe ich eine standard Procedure "free" eingeführt die das übernimmt. Ich habe damit noch mal verschiedene tests durchgeführt: -Erstellung und implizite conversion nach string - OK -Vergleich rec1 vs rec2 -OK -Vergleich a:=trec.create </=/> b:=trec.create - OK -Länge, conversion nach byte / integer - OK !: -Vergleich: trec vs uint - n. OK, da hier für das uint eine conversion durchgeführt wird. Ich denke mal, ich müsste evtl die implizite conversion hier umkehren, um keine dangling variable zu haben? Danke für den Tip mit der Tlist. ich war der Meinung, dass man da immer hin und her kopieren müsste, daher dachte ich mir die verkettete liste sei ggf. einfacher zu handeln (also einfügen,löschen etc durch einfaches umbiegen) und hätte weniger Overhead. Zitat:
|
AW: Custom Record Freigabe verkettete liste
Managed sind die neuen Records, wenn du die dazu machst und die 3 neuen Operatoren ordentlich benutzt.
was echtes/automatisches "managed" betrifft, welches es schon seit jahrzehnten gibt. mit Strings gab es immer die wenigsten Probleme, aber darin Binärdaten zu verwalten ist nicht immer einfach. Was ich aber seit Jahren gut nutzen könnte war ein
Delphi-Quellcode:
mit der Länge 0 oder 1.
F: TArray<record ... end>;
Das funktionierte sowohl im Windows, also auch genau gleich im NextGen (Android und bestimmt auch iOS) Man muß nur wissen, das Arrays (außer bei den Strings) kein CopyOnWrite besitzen, wenn man auf Felder des Arrays schreibend zugreift. Also wenn soeine Recordvariable kopiert wurde, dann wurden nur die Arrayzeiger kopiert und der ReferenzCounter erhöht, welches man aber beim Aufruf einer Recordmethode vor dem Zugriff prüfen kann, falls es nötig ist. Jetzt, mit den neuen CustomManaged-Operatoren, kann man da nun geziehlt drauf reagieren, direkt beim Kopieren alles so behandeln, wie man es für nötig hält. Ansonsten sind die neuen "Custom Managed Records" eine super Sache und erleichtern theoretisch die Speicherverwaltung enorm (so lange man nicht drauf angewiesen ist ältere Delphi-Versionen unterstüzen zu müssen, z.B. bei der Komponentenentwicklung) Aber DU mußt eben mit den 3 neuen Funktionen (Initialize/Copy/Finalize) ordentlich arbeiten (viel üben) und dann haben die Records ein echt gutes Potential. Ein Projekt mit einer mehrfach verketteten Liste hatte ich auch nun endlich mal wieder angefangen neu zu überarbeiten, aber ich kann mich seit Gestern nicht mehr mit meinem Computer daheim verbinden. Hatte die letzten Jahre viel mit den oben genannten Krücken gearbeitet, aber die ersten Tests mit den neuen CustomManaged-Operatoren sahen eigentlich sehr gut aus. jupp, virtueller Destructor ist nicht und falls man es benötigt, muß man sich selber eine Referenzzählung bauen oder eben nochmals ein Interface im Record verpacken, falls mehrere Variablen auf den gleichen Inhalt zeigen können. also wenn man intern mit "ungemanagten" Pointern arbeitet, dann muß man schon sehr aufpassen und viel beachten. (wie gesagt, meine Hilfe/Krücke war bisher TArray<> mit Länge 1 und dessen Referenzzählung) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:27 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz