![]() |
selbstlöschenden Pointer erstellen
Im Prinzip geht es darum, daß man hier "r" manuell freigeben muß.
Delphi-Quellcode:
Also hab ich mal versucht, dieses zu automatisieren.
Type TX = Record
a: Integer; r: ^TFormatSettings; End; 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:
Und die nötigen Klassen:
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.
Delphi-Quellcode:
Nunja, grundsätzlich läuft dieses erstmal, auch wenn ich noch einiges ändern werde:
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. - 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. :angel2: Folgendes ist ja leider nicht nutzbar, auch wenn ich, Aufgrund von Implicit wenigstens einen Lesezugriff erwartet hätte. :? Zitat:
Nun die Fragen: - Ist sowas überhaupt ausbaufähig aka könnten Andere sowas mal gebrauchen? - Hat jemand Ideen, Vorschläge, Kritik? - ... |
Re: selbstlöschenden Pointer erstellen
Hi himitsu,
warum so einen Aufwand. Deklariere TX doch einfach als Klasse. als Record:
Delphi-Quellcode:
als Klasse:
Type TX = Record
a: Integer; r: ^TFormatSettings; End;
Delphi-Quellcode:
type
TX = Class a: Integer; r: ^TFormatSettings; Constructor create; Destructor destroy; End; ..... Constructor TX.create; begin New(r); end; Destructor TX.destroy; begin dispose(r); end; Es mag jetzt vielleicht formal nicht alles richtig sein aber prinzipiell müsste das so funktionieren. Grüsse Rainer |
Re: selbstlöschenden Pointer erstellen
Nja, ich hatte den Record jetzt "nur" als Container genommen, um den Code irgendwo einzubauen zu können.
Auch wenn ich dieses vorwiegend für Records geplant hatte. PS: Wenn man es genau nimmt, dann ist hier ja nun schon ein Objekt beteiligt, auch wenn es sich hinter einem Interface und an anderer Stelle versteckt. Es gibt ja dennoch Unmassen an Recordstrukturen, auch wenn einem förmlich immer und überall Objekte aufgezwungen werden. Im Prinzip ware es ja nun so, als wenn man für diesen Teilcode sowas wie einen Garbage Collector hätte. |
Re: selbstlöschenden Pointer erstellen
Dadurch, dass Delphi jetzt aber quasi erraten muss wann im Hintergrund freigegeben werden muss, handelst du dir allerdings nicht nur Nachteile bei der Geschwindigkeit ein (schau dir mal den generierten zusätzlichen Code für die Referenzzählung z.B. an). Wenn jetzt noch an der falschen Stelle Exceptions auftreten, dann funktioniert auch die Freigabe nicht mehr. Bei Klassen wäre das kein Problem, weil diese durch Ressourcenschutzblöcke explizit freigegeben werden. Wenn aber der implizite Freigabecode durch die Exception übersprungen wird, nicht.
Deshalb ist es auch beim Arbeiten mit Interfaces der Windows API oder eigenen manchmal nicht ganz einfach die Freigabe sicherzustellen, so dass man da auch manuell Hand anlegen muss. (Sprich: in finally die Variablen auf nil setzen z.B.) Zitat:
Zudem hast du selbst von Konstruktoren für Records gesprochen. Das macht aber ganz einfach keinen Sinn, da es dann keinen fühlbaren Unterschied mehr zur Klasse gäbe. Genau dafür sind Klassen eben da. |
Re: selbstlöschenden Pointer erstellen
Zitat:
P.S.: Operator Überladung funktioniert imho auch nur mit Records |
Re: selbstlöschenden Pointer erstellen
Zitat:
Delphi-Quellcode:
FinalizeRecord wird hier doch eh immer beim END; aufgerufen, solange entsprechende Teile (Strings, dyn. Array oder Interfaces) enthalten sind.
procedure test;
var x: TMyRecord; begin end; Und genau da könnte man leicht auch einen Record-Destructor integrieren ... einfach nur wie einen virtuellen Datentypen in der RTTI des Records. ![]() Da es sowas aber nicht in Delphi gibt. Uber den obengenannten Typen kann man grundsärtlich erstmal jeden Record-Pointer in ein Interface umwandeln. Wenn die Records solche Constructoren/Destructoren hätten, dann könnte man sie qusa als eine Mischung aus Interface und Objekt ansehn. Schnelle Funktionsaufrufe über statische Prozeduren (wie bei Objekten ohne die ganzen virtuellen Prozeduren und ohne den Verwaltungsoverhead der Vererbungshirachie. Und dennoch automatische Freigaben, wie bei Interfaces. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:37 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-2025 by Thomas Breitkreuz