Im Prinzip geht es darum, daß man hier "r" manuell freigeben muß.
Delphi-Quellcode:
Type TX = Record
a: Integer;
r: ^TFormatSettings;
End;
Also hab ich mal versucht, dieses zu automatisieren.
Aber so ganz Glücklich bin ich mit meiner ersten Lösung noch nicht.
OK, eine Anfrage bei Emba, ob die nicht mal einen Constructor und vorallem einen Destructor für Records implementieren können ist gestellt, aber eine Antwort gab es bißher noch nicht und ob es jemals sowas geben wird ......
Gut, also kann man nur noch die Compilermagic und andere sich selbst freigebende Dinge verwenden.
Da wären also Strings, dynamische Arrays und Interfaces.
Ich hab mich natürlich für das Interface entschieden.
Hier also nochmal der selbe Record von oben, nur eben mit einem Interface dazwischen:
Delphi-Quellcode:
Program Project4;
{$APPTYPE CONSOLE}
Uses SysUtils, Unit4;
Type TX =
Record
a: Integer;
r: TSelfDestrucionPointer<TFormatSettings>;
End;
Var X: TX;
F: TFormatSettings;
Begin
Try
X.r.Alloc;
X.r.PData^.NegCurrFormat := 2;
If X.r.Data.NegCurrFormat = 1
Then ;
F := X.r;
If F.NegCurrFormat = 1
Then ;
Except
On E:
Exception do
WriteLn(E.ClassName, '
: ', E.
Message);
End;
End.
Und die nötigen Klassen:
Delphi-Quellcode:
Unit Unit4;
Interface
Type IInternalSelfDestrucionPointer =
Interface
Function Data: Pointer;
End;
TInternalSelfDestrucionPointer =
Class(TInterfacedObject, IInternalSelfDestrucionPointer)
Protected
_TypeInfo: Pointer;
_Data: Pointer;
Public
Constructor Create(Size: Integer; TypeInfo: Pointer);
Destructor Destroy;
Override;
Function Data: Pointer;
End;
TSelfDestrucionPointer<Typ> =
Record
Private
_Data: IInternalSelfDestrucionPointer;
Type PTyp = ^Typ;
Procedure SetData(
Const Data: Typ);
Function GetData: Typ;
Function GetPData: PTyp;
Public
Class Operator Implicit(
Const X: TSelfDestrucionPointer<Typ>): Typ;
Class Operator Implicit(
Const X: Typ): TSelfDestrucionPointer<Typ>;
Property Data: Typ
Read GetData
Write SetData;
Property PData: PTyp
Read GetPData;
Procedure Alloc;
Procedure Free;
End;
Implementation
Constructor TInternalSelfDestrucionPointer.Create(Size: Integer; TypeInfo: Pointer);
Begin
_Data := GetMemory(Size);
_TypeInfo := TypeInfo;
FillChar(_Data^, Size, 0);
End;
Destructor TInternalSelfDestrucionPointer.Destroy;
Begin
FinalizeArray(@_Data, _TypeInfo, 1);
FreeMemory(_Data);
End;
Function TInternalSelfDestrucionPointer.Data: Pointer;
Begin
Result := _Data;
End;
Procedure TSelfDestrucionPointer<Typ>.SetData(
Const Data: Typ);
Begin
If not Assigned(_Data)
Then
_Data := TInternalSelfDestrucionPointer.Create(SizeOf(Typ), TypeInfo(Typ));
PTyp(_Data.Data)^ := Data;
End;
Function TSelfDestrucionPointer<Typ>.GetData: Typ;
Begin
If not Assigned(_Data)
Then Begin
Finalize(Result);
FillChar(Result, SizeOf(Typ), 0);
End Else Result := PTyp(_Data.Data)^;
End;
Function TSelfDestrucionPointer<Typ>.GetPData: PTyp;
Begin
If not Assigned(_Data)
Then Result :=
nil
Else Result := PTyp(_Data.Data);
End;
Class Operator TSelfDestrucionPointer<Typ>.Implicit(
Const X: TSelfDestrucionPointer<Typ>): Typ;
Begin
If not Assigned(X._Data)
Then Begin
Finalize(Result);
FillChar(Result, SizeOf(Typ), 0);
End Else Result := PTyp(X._Data.Data)^;
End;
Class Operator TSelfDestrucionPointer<Typ>.Implicit(
Const X: Typ): TSelfDestrucionPointer<Typ>;
Begin
Result._Data := TInternalSelfDestrucionPointer.Create(SizeOf(Typ), TypeInfo(Typ));
PTyp(Result._Data.Data)^ := X;
End;
Procedure TSelfDestrucionPointer<Typ>.Alloc;
Begin
_Data := TInternalSelfDestrucionPointer.Create(SizeOf(Typ), TypeInfo(Typ));
End;
Procedure TSelfDestrucionPointer<Typ>.Free;
Begin
_Data :=
nil;
End;
End.
Nunja, grundsätzlich läuft dieses erstmal, auch wenn ich noch einiges ändern werde:
- der Typ/Record muß noch direkt in die Objektinstanz rein
(ein Speicherblock reicht ja ... jetzt sind es noch 2 ... einmal der Record und dann noch das Objekt)
Nur leider ist es nicht möglich dem Interface-Zeiger und dem Pointer auf den Record den den selben Wert zu geben
Gut, also die selben "Zeiger" sind also nicht möglich, aber wenn ich es wenigstens schaffe die Zugriffe, bzw. die Befehle für den Zugriff, halbwegs identisch aussehn zu lassen (vom Quellcode her), dann wäre es für meine Zwecke schonmal nutzbar.
Folgendes ist ja leider nicht nutzbar, auch wenn ich, Aufgrund von Implicit wenigstens einen Lesezugriff erwartet hätte.
Zitat:
X.r.NegCurrFormat
X.r^.NegCurrFormat
Nun die Fragen:
- Ist sowas überhaupt ausbaufähig aka könnten Andere sowas mal gebrauchen?
- Hat jemand Ideen, Vorschläge, Kritik?
- ...