AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein selbstlöschenden Pointer erstellen
Thema durchsuchen
Ansicht
Themen-Optionen

selbstlöschenden Pointer erstellen

Ein Thema von himitsu · begonnen am 28. Mär 2010 · letzter Beitrag vom 29. Mär 2010
Antwort Antwort
Benutzerbild von himitsu
himitsu

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

selbstlöschenden Pointer erstellen

  Alt 28. Mär 2010, 20:35
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?
- ...
$2B or not $2B
  Mit Zitat antworten Zitat
R2009

Registriert seit: 9. Mär 2009
Ort: Heidelberg
440 Beiträge
 
Delphi 2007 Professional
 
#2

Re: selbstlöschenden Pointer erstellen

  Alt 29. Mär 2010, 06:50
Hi himitsu,
warum so einen Aufwand. Deklariere TX doch einfach als Klasse.

als Record:

Delphi-Quellcode:
Type TX = Record
    a: Integer;
    r: ^TFormatSettings;
  End;
als Klasse:

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
Rainer Unger
Mein Profil:
Studium Allgemeine Elektrotechnik TH Darmstadt
Entwicklung von Tools für die Rundsteuer und Zählertechnik.
uP's Atmel Prozessoren (ATmega16,32,88...) in C und Assembler.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

Re: selbstlöschenden Pointer erstellen

  Alt 29. Mär 2010, 07:01
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.
$2B or not $2B
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.648 Beiträge
 
Delphi 11 Alexandria
 
#4

Re: selbstlöschenden Pointer erstellen

  Alt 29. Mär 2010, 08:54
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 von himitsu:
Im Prinzip ware es ja nun so, als wenn man für diesen Teilcode sowas wie einen Garbage Collector hätte.
Genau das ist eben das Problem: Ein GC sucht (je nach Implementierung) im Hintergrund nicht nur nach Referenzzählern, sondern prüft auch worauf noch Zeiger zeigen usw., so dass er eben nicht nur von ständig zusätzlich ausgeführtem Code abhängt. Das heißt es ist dann egal ob eine Exception auftritt, außerdem wird der Code dadurch nicht langsamer.

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.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.027 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#5

Re: selbstlöschenden Pointer erstellen

  Alt 29. Mär 2010, 09:16
Zitat von jaenicke:
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.
Es macht sehr wohl einen Unterschied, weil es im Moment ohne gewisse Tricks (z.B. Interfaces und die von dir angesprochenen Gefahren) z.B. nicht möglich ist das RAII Idiom in Delphi umzusetzen. Außerdem hat man bei simplen Objekten immernoch den .Create "Overhead" und kann nicht einfach wie z.B. in C++ Objekte auf dem Stack erzeugen. Und nur Konstruktoren für Records (wenn auch nur parametrisierte) und keine Destruktoren, halte ich für inkonsequent.

P.S.: Operator Überladung funktioniert imho auch nur mit Records
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

Re: selbstlöschenden Pointer erstellen

  Alt 29. Mär 2010, 11:16
Zitat von Stevie:
Und nur Konstruktoren für Records (wenn auch nur parametrisierte) und keine Destruktoren, halte ich für inkonsequent.
Dabei muß es garnicht so schwer sein sowas zu implementieren.

Delphi-Quellcode:
procedure test;
var x: TMyRecord;
begin
end;
FinalizeRecord wird hier doch eh immer beim END; aufgerufen, solange entsprechende Teile (Strings, dyn. Array oder Interfaces) enthalten sind.
Und genau da könnte man leicht auch einen Record-Destructor integrieren ... einfach nur wie einen virtuellen Datentypen in der RTTI des Records.

http://qc.embarcadero.com/wc/qcmain.aspx?d=82524

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.
$2B or not $2B
  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 02:36 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