Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Methode "Free" selbst implementieren (Assembler-Problem?) (https://www.delphipraxis.net/40867-methode-free-selbst-implementieren-assembler-problem.html)

VizeTE 22. Feb 2005 11:56


Methode "Free" selbst implementieren (Assembler-Pr
 
Hallo,

Alle von TObject abgeleiteten Klassen können per Free freigegeben werden ohne das es zu einer Exception kommt falls das entprechende Objekt nicht instanziert wurde/nil ist. Ich möchte selbst ein Free implementieren ohne diese Eigenschaft zu verlieren.
Bisher habe ich folgenden Code
Delphi-Quellcode:
TMyList = class(TList)
protected
  FDoSomething : boolean;
public
  destructor Destroy; override;
  procedure Free(DoSomething : boolean); reintroduce;
end;

destructor TMyList.Destroy;
begin
  if FDoSomething then
  begin
    ...do something...
  end;
  inherited;
end;

procedure TMyList.Free(DoSomething: boolean);
asm
  TEST   EAX,EAX
  JE     @@exit
  MOV    ECX,[EAX]
  MOV    DL,1
  CALL   dword ptr [ECX].vmtDestroy
  @@exit:
end;
Den Assembler-Code habe ich mir von TObject kopiert ohne wirklich zu wissen was er macht (wobei man die ersten beiden und letzten beiden Zeile ja erahnen kann). Das funktioniert auch soweit.
Falls der Parameter "DoSomething" der Methode "Free" gesetzt (wahr) ist soll in "Destroy" entsprechend reagiert werden.
Was ich jetzt nicht weiß ist wie ich meine Objektvariable in "Free" entsprechend dem Parameter setzen kann.

Falls jemand eine Idee hat oder mir sagen kann wo ich sowas nachlesen kann oder einen einfacheren Ansatz hat würde ich mich freuen :lol:
(Die Variable vor dem Aufruf von "Free" per property zu setzen würde sicher auch gehen, daß wollte ich aber vermeiden damit der Programmieren das nicht vergessen kann)

Ciao

Dax 22. Feb 2005 12:07

Re: Methode "Free" selbst implementieren (Assemble
 
Wieso den komplizierten Assembler hernehmen? So gehts doch auch, und dein Problem löst es gleich mit :)

Delphi-Quellcode:
destructor TMyList.Destroy(DoSomething: boolean);
begin
  if Self <> nil then
  begin
    fDoSemthing := DoSomething;
    Destroy;
  end
end;

jim_raynor 22. Feb 2005 12:12

Re: Methode "Free" selbst implementieren (Assemble
 
1. Würde ich diese Funktion nicht Free nennen. Früher oder Später wird es nur Verwirrungen geben.

2. Kannst du ganz einfach mit

Delphi-Quellcode:
if Self=nil then
die Prüfung machen.

3. Entfällt 2 dann, weil du Free direkt aufrufen kannst, wenn du deiner Funktion einen anderen Namen gibts.

himitsu 22. Feb 2005 12:17

Re: Methode "Free" selbst implementieren (Assemble
 
Schau mal dort rein, da dein Free jetzt einen Parameter besitzt, wird da vom Compiler noch zusätzlicher Code eingefügt, welcher jetzt vermutlich mit deinem AssemblerCode etwas in Konflickt gerät.

Inline Assembler und automatische Optimierung?



(oder du hast einfach nur einen Fehler beim Abschreiben gemacht)

VizeTE 22. Feb 2005 12:44

Re: Methode "Free" selbst implementieren (Assemble
 
@Dax

In der Tat, einfacher geht es nicht.:wall: (Wobei ich dann die Prüfung in der Methode "Free" durchführe, aber ich denke das wolltest du auch schreiben da du innerhalb des if-Blockes ja Destroy aufrufst) Als ich rumgetestet habe und noch Pascal statt Assembler verwendete hatte ich Free wohl noch als virtual gekennzeichnet. Von daher ging das nicht (Exception beim Aufruf ohne in die Methode zu springen). Dann habe ich wohl den Assembler-Code kopiert und das virtual entfernt und die Schuld fälschlicherweise auf den Pascal-Code geschoben)

@jim_raynor

Mein Gedanke bei der Benennung der Methode war halt der, daß jeder weiß, daß er ein instantiertes Objekt wieder mit Free freigeben muß. Wenn man dieses Objekt benutzt und Free aufruft meckert dann der Compiler, daß der Parameter fehlt. So weiß derjenige dann:
1. ja, er muß Free aufrufen
2. zum Aufruf ist ein Parameter nötig (der dann natürlich nicht DoSomething heißt sondern erkennen läßt was er tut!)
Natürlich fehlt dann hier noch "inherited Free;", sodaß meine Methode jetzt so aussieht:
Delphi-Quellcode:
procedure TMyList.Free(ADoSomething: boolean);
begin
  if Self <> nil then
  begin
    FDoSomething := ADoSomething;
    inherited Free;
  end;
end;
Deshalb habe ich ja auch "Free" mit reintroduce" gekennzeichnet. Somit gibt es nur das eine "Free" und Verwirrungen sind somit minimiert. (Zumindest würde es mich mehr verwirren wenn es auf einmal 2 Free-Methoden gibt!)

Ich denke so sollte das gehen. Falls noch Einwände bestehen würde ich mich über Eure Meinung freuen.

PS: Vielen Dank für die superkurze Antwortzeit!

VizeTE 22. Feb 2005 12:51

Re: Methode "Free" selbst implementieren (Assemble
 
@himitsu

Noch ein Grund das ohne Assembler zu lösen :wink:
Wie gesagt, ich habe keine Ahnung von Assembler.

sakura 22. Feb 2005 13:04

Re: Methode "Free" selbst implementieren (Assemble
 
Benenne die Methode trotzdem nicht Free, weil Free von Delphi an den verschiedensten Stellen genutzt wird und dabei von der Festen "Methoden-Signatur" ohne Parameter ausgegangen wird. Wenn die Free jetzt Parameter gibt (warum eigentlich), dann machst Du es für andere Entwickler nur umständlicher mit Deinen Objekten zu arbeiten.

...:cat:...

Neutral General 22. Feb 2005 13:25

Re: Methode "Free" selbst implementieren (Assemble
 
Aber warum willst du eigentlich ein eigenes Free ? :gruebel:

VizeTE 22. Feb 2005 14:22

Re: Methode "Free" selbst implementieren (Assemble
 
@Neutral General

Zitat:

Aber warum willst du eigentlich ein eigenes Free ?
Weil ich einen Parameter übergeben möchte und dabei vermieden werden soll,daß es viele Free-Methoden gibt. Normalerweise sieht man je wegen einem Free nicht extra in der Dokumentation nach was das tolles macht oder nicht macht sondern schreibt es einfach hin und gut. Wenn es aber nur meine Free gibt dann sieht das halt anders aus.


@sakura

Zitat:

enenne die Methode trotzdem nicht Free, weil Free von Delphi an den verschiedensten Stellen genutzt wird und dabei von der Festen "Methoden-Signatur" ohne Parameter ausgegangen wird.
Wäre es denn ok wenn ich den Parameter einen Defaultwert geben und mein Free somit wie das ursprüngliche Free aufgerufen werden kann? Wäre zwar nicht ganz in meinem Sinne aber, in meinen Augen, ein funktionierender Kompromiß.

MaBuSE 22. Feb 2005 14:26

Re: Methode "Free" selbst implementieren (Assemble
 
Folgende "einfache" Lösung ist auch möglich.

Delphi-Quellcode:
TMyList = class(TList)
public
  DoSomething : boolean;
  destructor Destroy; override;
end;

destructor TMyList.Destroy;
begin
  if DoSomething then
  begin
    ...do something...
  end;
  inherited;
end;
Dann kannst Du einfach mit folgenden Zeilen Deinen Zweck erfüllen.
Delphi-Quellcode:
...
var
  ml : TMyList;
...
begin
  ...
  ml := TMyList.Create;
  ...
  ml.DoSomething := True;
  ...
  ml.Free;
  ml := Nil;
  ...
end;
...
Die "ml := Nil" Zeile habe ich mir angewöhnt, da ein Free prüft ob das Objekt <> nil ist und es in diesem Fall freigibt. Danach ist aber das Objekt zwar freigegeben, aber nicht nil. Der Pointer zeigt immer noch auf die Spericherstelle wo das Objekt mal war. Ein erneuter Aufruf von Free kann dann Probleme machen.

sakura 22. Feb 2005 14:26

Re: Methode "Free" selbst implementieren (Assemble
 
Zitat:

Zitat von VizeTE
Wäre es denn ok wenn ich den Parameter einen Defaultwert geben und mein Free somit wie das ursprüngliche Free aufgerufen werden kann? Wäre zwar nicht ganz in meinem Sinne aber, in meinen Augen, ein funktionierender Kompromiß.

Auch das kann und wird wahrscheinlich im Laufe der Nutzung zu schwerz nachvollziehbaren Ausnahmefehlern führen. Free, genau wie auch Destroy ist eine der wenigen Methoden deren Parameter man nicht ändern soll/darf. Wozu muss mein beim Freigeben überhaupt Parameter überreichen. Entweder das Objekt ist schon tot oder es wird abgeknippst, keine weiteren Optionen...

...:cat:...

VizeTE 22. Feb 2005 14:29

Re: Methode "Free" selbst implementieren (Assemble
 
Es ging mir darum, daß eventuell an das Object angehangene Objekte ebenfalls freigegeben werden oder auch nicht. Je nachdem, ob diese noch benötigt werden/an andere Stelle referenziert sind.

MaBuSE 22. Feb 2005 14:31

Re: Methode "Free" selbst implementieren (Assemble
 
Zitat:

Zitat von VizeTE
Es ging mir darum, daß eventuell an das Object angehangene Objekte ebenfalls freigegeben werden oder auch nicht. Je nachdem, ob diese noch benötigt werden/an andere Stelle referenziert sind.

Dann sollte auch die "einfache" Lösung (s.o.) für Dich ausreichend sein.

VizeTE 22. Feb 2005 14:36

Re: Methode "Free" selbst implementieren (Assemble
 
Zitat:

Zitat von MaBuSE
Dann sollte auch die "einfache" Lösung (s.o.) für Dich ausreichend sein.

Das wollte ich vermeiden da man es einfach vergesssen könnte. (Besonders wenn jemand die Klasse nutzt der sie nicht entworfen hat. Woher soll der denn wissen das es dieses property gibt. Wegen einem Free sieht man ja, wie gesagt, nicht extra in die Dokumentation.

Dax 22. Feb 2005 14:39

Re: Methode "Free" selbst implementieren (Assemble
 
Dann setze dir doch ein Flag in der Klasse, sobald du irgendwas erstellst, das wieder freigeben werden muss. Dieses Flag fragst du dann im Destruktor ab und reagierst dann entsprechend..

VizeTE 22. Feb 2005 14:47

Re: Methode "Free" selbst implementieren (Assemble
 
Zitat:

Zitat von Dax
Dann setze dir doch ein Flag in der Klasse, sobald du irgendwas erstellst, das wieder freigeben werden muss. Dieses Flag fragst du dann im Destruktor ab und reagierst dann entsprechend..

Das wäre sicher eine Möglichkeit. Wahrscheinlich wird es auch darauf hinauslaufen wenn das mit dem eigenen Free so problematisch ist. Ich wollte dies nur vermeiden um dem vergessen des Flags vorzubeugen. (siehe einige Posts vorher)

Dax 22. Feb 2005 14:54

Re: Methode "Free" selbst implementieren (Assemble
 
Wenn du das Flag in der Klasse beim setzen einer Eigenschaft setzt, hast du dieses Problem schon gelöst ;) Was schon getan ist, kann man ja nicht mehr vergessen :) Oder hab' ich was falsch verstanden? :gruebel:

retnyg 22. Feb 2005 15:15

Re: Methode "Free" selbst implementieren (Assemble
 
weiss zwar nicht was da standardmässig in eax steht aber so könnte es gehen:

Delphi-Quellcode:
procedure dosomething;
begin
  showmessage('parameter wurde an free übergeben');
end;

procedure TObject.Free(myparam:boolean); stdcall;
asm
        TEST   EAX,EAX
        JE     @@exit
        MOV    ECX,[EAX]
        CALL   dword ptr [ECX].vmtDestroy
        pop eax
        cmp eax, 1 
        jne @@exit
        call dosomething
@@exit:
end;

VizeTE 22. Feb 2005 15:15

Re: Methode "Free" selbst implementieren (Assemble
 
Zitat:

Zitat von Dax
Wenn du das Flag in der Klasse beim setzen einer Eigenschaft setzt, hast du dieses Problem schon gelöst ;) Was schon getan ist, kann man ja nicht mehr vergessen :) Oder hab' ich was falsch verstanden? :gruebel:

Prinzipiell nicht falsch. Aber ist gibt halt Situationen wo gleiche Vorgänge unteschiedlich behandelt werden. Wenn ich zum Beispiel an zwei Objecte ein drittes "andocke" (an beiden das selbe) und das erste Objekt freigeben darf ich das angedockte Objekt nicht freigeben wenn ich es am zweiten Objekt noch benötige. (also identische Andockvorgänge aber zwei unterschiedliche Abdockvorgänge) Wie gesagt prinzipiell würde es gehen aber ich muß halt immer an das setzen des Flags denken. (was ich vermeiden wollte)

VizeTE 22. Feb 2005 15:22

Re: Methode "Free" selbst implementieren (Assemble
 
Zitat:

Zitat von retnyg
weiss zwar nicht was da standardmässig in eax steht aber so könnte es gehen:

Sorry, den Name DoSomething war wohl nicht besonders gut gewählt. Sollte eine Variable sein und von daher auch vor Destroy gesetzt werden da in Destroy darauf reagiert werden soll. (wenn ich den Assembler-Code richtig interpretiert habe)

retnyg 22. Feb 2005 15:44

Re: Methode "Free" selbst implementieren (Assemble
 
dann halt so:
Delphi-Quellcode:
procedure dosomething;
begin
  mydestroyvariable := true;
end;

procedure TObject.Free(myparam:boolean); stdcall;
asm
        pop edx
        cmp edx, 1 
        jne @@weiter
        call dosomething
@@weiter:
        TEST   EAX,EAX
        JE     @@exit
        MOV    ECX,[EAX]
        CALL   dword ptr [ECX].vmtDestroy
@@exit:
end;

MaBuSE 22. Feb 2005 15:49

Re: Methode "Free" selbst implementieren (Assemble
 
Folgendes "einfaches" Beispiel sollte Dein Problem lösen:

Unit1.pas
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;

type
  TMyObject = class;

  TMyObject = class(TForm)
    Timer1: TTimer;
    procedure Timer1Timer(Sender: TObject);
  private
    { Private-Deklarationen }
    MyRefCount: Integer;
  public
    { Public-Deklarationen }
    constructor Create(AOwner: TComponent); override;
    function GetMyObject: TMyObject;
    procedure FreeMyObject;
  end;

var
  MyObject: TMyObject;

implementation

{$R *.dfm}

{ TMyObject}

// Hier wird nur MyRefCount hochgezählt (auf 1 gesetzt)
constructor TMyObject.Create(AOwner: TComponent);
begin
  inherited;
  Inc(MyRefCount);
end;

// hiermit werden die Objekte freigegeben
procedure TMyObject.FreeMyObject;
begin
  if Self <> nil then
  begin
    Dec(MyRefCount);
    if MyRefCount < 1 then Self.Free;
  end;
end;

// hiermit wird eine Objektreferenz geholt
function TMyObject.GetMyObject: TMyObject;
begin
  if Self <> nil then
  begin
    Inc(MyRefCount);
    Result := Self;
  end
  else
  begin
    Result := nil;
  end;
end;

// Der Timer ist nur auf dem Form, damit man sieht wie viele Refs es gibt
procedure TMyObject.Timer1Timer(Sender: TObject);
begin
  Caption := IntToStr(MyRefCount);
end;

end.
Hier werden 3 wichtige Dinge implementiert:
  • Create wird überladen der der Referenzzähler auf 1 gesetzt
  • Mit GetMyObject wird das akive Object übergeben und der Referenzzähler um 1 erhöht
  • Mit FreeMyObject wird die aktive Referenz freigegeben und der Referenzzähler um 1 erniedrigt
Anwendung siehe Unit2:
Delphi-Quellcode:
unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm2 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    Button6: TButton;
    Button7: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure Button6Click(Sender: TObject);
    procedure Button7Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form2: TForm2;

implementation

uses Unit1;

{$R *.dfm}

var a, b : TMyObject;

procedure TForm2.Button1Click(Sender: TObject);
begin
  MyObject := TMyObject.Create(self);
  MyObject.Show;
end;

procedure TForm2.Button2Click(Sender: TObject);
begin
  a := MyObject.GetMyObject;
end;

procedure TForm2.Button3Click(Sender: TObject);
begin
  b := MyObject.GetMyObject;
end;

procedure TForm2.Button4Click(Sender: TObject);
begin
  a.FreeMyObject;
  a := nil;
end;

procedure TForm2.Button5Click(Sender: TObject);
begin
  b.FreeMyObject;
  b := nil;
end;

procedure TForm2.Button6Click(Sender: TObject);
begin
  MyObject.FreeMyObject;
  MyObject := nil
end;

procedure TForm2.Button7Click(Sender: TObject);
begin
  Close;
end;

end.
Die Unit 2 ist ein leeres TForm mit 7 TButtons
  • Button1 = MyObject erzeugen und anzeigen
  • Buttin2 = MyObject wird A zugewiesen
  • Buttin3 = MyObject wird B zugewiesen
  • Buttin4 = A wird freigegeben
  • Buttin5 = B wird freigegeben
  • Buttin6 = MyObject wird freigegeben
  • Button7 = Programmende
Egal in welcher Reihenfolge freigegeben wird, verschwindet das Fenster TMyObject erst, wenn die letzte Referenz freigegeben wurde.

Das Ganze wird in die Project1.dpr eingebunden:
Delphi-Quellcode:
program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {MyObject},
  Unit2 in 'Unit2.pas' {Form2};

{$R *.res}

begin
  Application.Initialize;
  Application.CreateForm(TForm2, Form2);
  Application.Run;
end.
Viel Spaß

[edit]
wichtig: Es muß natürlich erst der Button1 gedrückt werden, damit TMyObject.Create aufgerufen wird. ;-)
[/edit]

VizeTE 23. Feb 2005 08:14

Re: Methode "Free" selbst implementieren (Assemble
 
Zitat:

Zitat von MaBuSE
Egal in welcher Reihenfolge freigegeben wird, verschwindet das Fenster TMyObject erst, wenn die letzte Referenz freigegeben wurde.

Das ist ja mal ein ganz anderer Ansatz, sehr interessant. Da muß ich mal d'rüber nachdenken ob ich das auf meine Problemstellung anwenden kann. Aber auf jeden Fall erstmal vielen Dank für deine Mühe! :spin:

MaBuSE 23. Feb 2005 08:52

Re: Methode "Free" selbst implementieren (Assemble
 
Zitat:

Zitat von VizeTE
Zitat:

Zitat von MaBuSE
Egal in welcher Reihenfolge freigegeben wird, verschwindet das Fenster TMyObject erst, wenn die letzte Referenz freigegeben wurde.

Das ist ja mal ein ganz anderer Ansatz, sehr interessant. Da muß ich mal d'rüber nachdenken ob ich das auf meine Problemstellung anwenden kann. Aber auf jeden Fall erstmal vielen Dank für deine Mühe! :spin:

Das ist nur ein einfacher Ansatz. Das lässt sich natürlich auch noch beliebig ausbauen.

Bei .net gibt’s den GarbageCollector, der macht so was Ähnliches. (Nur viel komplizierter :mrgreen:)
Wenn es auf ein Objekt keine Referenz mehr gibt, dann wird es in die "Müllsammlung" gegeben und irgendwann später aus dem Speicher entfernt. Aber solange es mindestens eine Referenz gibt, bleibt es im Speicher.

jbg 23. Feb 2005 09:34

Re: Methode "Free" selbst implementieren (Assemble
 
Zitat:

Zitat von VizeTE
Wegen einem Free sieht man ja, wie gesagt, nicht extra in die Dokumentation.

Genau. Und was passiert wenn man dein Objekt in eine TObject Referenz steckt? Dann wird bei obj.Free das TObject.Free aufgerufen und nicht deine neue Version.

VizeTE 23. Feb 2005 11:36

Re: Methode "Free" selbst implementieren (Assemble
 
Zitat:

Zitat von jbg
Genau. Und was passiert wenn man dein Objekt in eine TObject Referenz steckt? Dann wird bei obj.Free das TObject.Free aufgerufen und nicht deine neue Version.

Probleme sehe ich dann nur wenn Delphi das an irgendeiner Stelle selbtständig macht. (Ich weiß nicht wann sowas passiert, gib mir doch mal bitte ein Beispiel [Meine Klasse ist von TList abgeleitet]).
Geht man davon aus, daß jemand das von Hand macht dann sollte man ja OOP vollständig vermeiden. Derjenige der sowas manuell macht sollte sich auch schlau machen welche Auswirkungen das hat, oder?
Wie würdest du denn das lösen?

maximov 23. Feb 2005 11:51

Re: Methode "Free" selbst implementieren (Assemble
 
Wenn dies alles dafür gedacht ist, objekte am leben zu erhalten, die noch referenziert werden, warum verwendest du dann nicht die automatisch COM-refCount geschichte? Du müsstest dann nur leider mit interface-refenren arbeiten.

VizeTE 23. Feb 2005 12:06

Re: Methode "Free" selbst implementieren (Assemble
 
Zitat:

Zitat von maximov
Wenn dies alles dafür gedacht ist, objekte am leben zu erhalten, die noch referenziert werden, warum verwendest du dann nicht die automatisch COM-refCount geschichte? Du müsstest dann nur leider mit interface-refenren arbeiten.

Nee, dafür war es nicht gedacht. Eigentlich wollte ich für Free einen Parameter übergeben mit dem entschieden wird ob Kind-Elemente ebenfalls freigegeben werden sollen. Ich wollte das nicht als Eigenschaft implementieren weil das für mich einfach eindeutiger erschien wenn es exakt ein Free gibt welches einen Parameter verlangt.

maximov 23. Feb 2005 15:24

Re: Methode "Free" selbst implementieren (Assemble
 
Zitat:

Zitat von VizeTE
Zitat:

Zitat von maximov
Wenn dies alles dafür gedacht ist, objekte am leben zu erhalten, die noch referenziert werden, warum verwendest du dann nicht die automatisch COM-refCount geschichte? Du müsstest dann nur leider mit interface-refenren arbeiten.

Nee, dafür war es nicht gedacht. Eigentlich wollte ich für Free einen Parameter übergeben mit dem entschieden wird ob Kind-Elemente ebenfalls freigegeben werden sollen. Ich wollte das nicht als Eigenschaft implementieren weil das für mich einfach eindeutiger erschien wenn es exakt ein Free gibt welches einen Parameter verlangt.

IMO macht es mehr sinn, das innerhalb der objekt-beziehungen die besitzansprüche genau geklärt sind und somit nur objekte freigegeben werden, die einem auch tatsächlich gehören. Diese lösung mit dem parameter erscheint mir mehr als unglücklich. Mir ist kein fall bekannt, bei dem ein delphi-priogrammierer gezwungen war einen ähnlichen weg zu gehen. IMO sind Free und Destroy unantastbar.

VizeTE 24. Feb 2005 08:15

Re: Methode "Free" selbst implementieren (Assemble
 
Zitat:

Zitat von maximov
IMO macht es mehr sinn, das innerhalb der objekt-beziehungen die besitzansprüche genau geklärt sind und somit nur objekte freigegeben werden, die einem auch tatsächlich gehören. Diese lösung mit dem parameter erscheint mir mehr als unglücklich. Mir ist kein fall bekannt, bei dem ein delphi-priogrammierer gezwungen war einen ähnlichen weg zu gehen. IMO sind Free und Destroy unantastbar.

Jaja, da habe ich mich ja schon überzeugen lassen. Nun bin ich am überlegen ob ich das halt doch vorher per Property mache (wie in TObjectList), versuche das mit dem RefCount umzusetzen oder vielleicht laß ich das Objekt wissen wem es gehört. Dann könnten die Listen nur die Eigenen freigeben. Das ist vielleicht die flexibelste Möglichkeit.

VizeTE 24. Feb 2005 09:45

Re: Methode "Free" selbst implementieren (Assemble
 
Ich glaube ich habe jetzt eine bessere Methode und hoffe das die hier mehr Zuspruch findet :wink: [Nochmal vielen Dank an maximov, das war wohl der entscheidende Tip]
Ich übernehme einfach das Owner-Modell von TComponent.

Besitzt ein Objekt keinen Owner und wird meiner Liste hinzugefügt so wird automatisch die Liste als Owner gesetzt.
Besitzt es bereits einen Owner so bleibt dieser unangetastet. Soll das Objekt nie freigegeben werden so trage ich als Owner einfach sich selbst an. (Dann ist es quasi vogelfrei, wie mal irgendein Papst das ausgedrückt hat)

Wenn ich die Liste dann freigebe werden alle Objekte die der Liste gehören freigegeben, klar.

Und das Besete an der Lösung: Ich kann die Liste auch noch für alle von TComponent abgeleitete Elemente verwenden. Das ich da nicht gleich d'rauf gekommen bin! :wall:

Oder seht ihr hier Probleme?

maximov 24. Feb 2005 10:15

Re: Methode "Free" selbst implementieren (Assemble
 
Zitat:

Zitat von VizeTE
....
Besitzt ein Objekt keinen Owner und wird meiner Liste hinzugefügt so wird automatisch die Liste als Owner gesetzt.
Besitzt es bereits einen Owner so bleibt dieser unangetastet. Soll das Objekt nie freigegeben werden so trage ich als Owner einfach sich selbst an. (Dann ist es quasi vogelfrei, wie mal irgendein Papst das ausgedrückt hat)
...

Sich selbst als Owner zu setzen ist vielleicht ein bisschen unglücklich. Das könnte zu rekursionen führen, die nicht gewollt sind. Ich würde den einfach NIL setzen, als zeichen das er niemanden gehört.

An sonsten hört sich das vernünftig an :)

VizeTE 24. Feb 2005 10:33

Re: Methode "Free" selbst implementieren (Assemble
 
Zitat:

Zitat von maximov
...Ich würde den einfach NIL setzen, als zeichen das er niemanden gehört.

mmm...dann muß ich aber den Ansatz verwerfen, daß Elemente die einer Liste hinzugefügt werden und keinen Owner haben automatisch Kinder dieser Liste werden. :cry:

maximov 24. Feb 2005 11:43

Re: Methode "Free" selbst implementieren (Assemble
 
Zitat:

Zitat von VizeTE
Zitat:

Zitat von maximov
...Ich würde den einfach NIL setzen, als zeichen das er niemanden gehört.

mmm...dann muß ich aber den Ansatz verwerfen, daß Elemente die einer Liste hinzugefügt werden und keinen Owner haben automatisch Kinder dieser Liste werden. :cry:

Warum? Das bietet sich doch erstrecht an:
Delphi-Quellcode:
procedure liste.fügehinzu(element)
begin
  TuInListe(element);
  if element.besitzer = nil then
    element.besitzer = mirSelbst;
end;
oder so. Frage mich wo das problem liegt. Allerdings kenne ich deine implementierung auch nicht.

VizeTE 24. Feb 2005 12:05

Re: Methode "Free" selbst implementieren (Assemble
 
Zitat:

Zitat von maximov
Warum? Das bietet sich doch erstrecht an:
Delphi-Quellcode:
procedure liste.fügehinzu(element)
begin
  TuInListe(element);
  if element.besitzer = nil then
    element.besitzer = mirSelbst;
end;

Das Problem ist, daß ich bei dieser Implementation nicht festlegen kann, daß ein Element nie zu einer List gehören soll da jedes Element welches keinen Besitzer hat automatisch der List zugeordnet wird.
Würde ich das freie Element mit Owner=ichselber angeben so würde es nicht nil sein und von der Liste nicht adoptiert werden.

Meine Idee wäre es, den Owner nicht automatisch von der Liste vergeben zu lassen (obwohl das komfortabler wäre) sondern das beim Konstruktor als Parameter anzuhängen.

maximov 24. Feb 2005 13:45

Re: Methode "Free" selbst implementieren (Assemble
 
Aber irgend einen owner muss ein objekt doch haben. Und wenn es keinen habenm soll, dann füge es nirgends ein.

Zitat:

Meine Idee wäre es, den Owner nicht automatisch von der Liste vergeben zu lassen (obwohl das komfortabler wäre) sondern das beim Konstruktor als Parameter anzuhängen.
so wie bei TCompoennt? Dort wird es im prinzip ähnlich gemacht:
Delphi-Quellcode:
constructor TComponent.Create(AOwner: TComponent);
begin
  FComponentStyle := [csInheritable];
  if AOwner <> nil then AOwner.InsertComponent(Self); // <-- AOwner.InsertComponent
end;

...
procedure TComponent.InsertComponent(AComponent: TComponent);
begin
  ...
  Insert(AComponent); // <-- Insert
  ...
end;

...
procedure TComponent.Insert(AComponent: TComponent);
begin
  if FComponents = nil then FComponents := TList.Create;
  FComponents.Add(AComponent);
  AComponent.FOwner := Self;
end;
...nur das auf die prüfung verzichtet wird.

Aber, darf ich fragen, worauf dein klassen-model (fals du eins hast) im endeffekt hinaus laufen soll? Was willst du realisieren? Wenn wir das wissen, dann können wir das problem evtl. viel gezielter lösen :wink:

VizeTE 3. Mär 2005 14:52

Re: Methode "Free" selbst implementieren (Assemble
 
Hallo,

also mein Plan ist folgender...
Ich möchte eine List schaffen, welche Objekt beinhaltet und dabei möglichst flexibel und automatisch ihre Items verwaltet. Dabei soll berücksichigt werden, daß Items der Liste selbst wieder Listen beinhalten und deren Elemente eventuell ebenfalls freigegeben werden.

Meine ursprüngliche Idee mit den Elementen ohne Owner war die, daß auch Elemente in einer Liste hinzugefügt werden können ohne das sie zu jemanden gehören. Dazu hatte ich zunächst die Möglichkeit in Betracht gezogen einfach den Owner auf nil zu setzen. Dann könnte ich aber nicht Elemente die einer Liste hinzugefügt werden automatisch adoptieren. Alternativ könnte man ja auch die freien Elemente einfach das Objekt wo es ersetellt wurde als Owner mitgeben. Da bin nich mir aber noch nicht richtig schlüssig welche Variante die bessere ist.

maximov 3. Mär 2005 16:09

Re: Methode "Free" selbst implementieren (Assemble
 
Mit anderen worten: Du willst eine baum-komposition (Kompositum) realisieren -> http://www.dofactory.com/Patterns/PatternComposite.aspx

sowas? Der code dort lässt sich bestimmt leicht adaptieren.

Was mich interessiert ist, ob die objekte in deiner list nur eine liste haben sollen, oder mehrere? Kann ein objekt in mehreren listen enthalten sein?

Wenn ein objekt zB. in einer liste ist, die nicht der owner ist, so hat sie keine möglichkeit sich dort automatisch zu entfernen, wenn es freigegeben wird. Für dieses problem kann man prima Observer (oder Refenzzählung) einsetzen.

Wie auch immer. In TComponent sind beide konzepte verbaut (Child/owner und RegisterNotification). Das ist sehr lehrreich, auch wenn die implementierung schon fast als historisch betrachtet werden muss.

Machst du das nur just-for-fun oder dient das einem höheren ziel? Denn dann könnte man das noch ein bisschen konkreter betrachten :wink:

VizeTE 4. Mär 2005 08:13

Re: Methode "Free" selbst implementieren (Assemble
 
Zitat:

Zitat von maximov
Was mich interessiert ist, ob die objekte in deiner list nur eine liste haben sollen, oder mehrere? Kann ein objekt in mehreren listen enthalten sein?
...
Machst du das nur just-for-fun oder dient das einem höheren ziel? Denn dann könnte man das noch ein bisschen konkreter betrachten

Ja, Objekt sollen in mehreren Listen vorkommen dürfen und Objekte sollen selbst mehrere Listen haben können.
Zur Zeit mach ich das mehr oder weniger just-for-fun, mit dem Ziel, daß später ernsthaft einzusetzen. Von daher möchte und kann ich hier keine konkreten Ziele nennen. Ich versuche es möglichst allgemein zu halten um die Lösung dann später auf möglichst viele Probleme anwenden zu können.

Mit den Links zu den Pattern kann ich leider nichts anfangen. Entweder liegt das am Server oder am aspx (habe ich bisher noch keine Erfahrungen, muß ich da bestimmte Voraussetzungen erfüllen (PlugIns...)?). Aber ich denke der Referenzzähler kommt nicht in Frage da die Objekte ja auch ohne Liste existieren können sollen. Das andere Pattern muß ich mir dann nochmal anschauen.

maximov 4. Mär 2005 10:58

Re: Methode "Free" selbst implementieren (Assemble
 
OK! Da hast du dir eine schöne aufgabe gesucht. Willst du mit interfaces arbeiten, oder komplett ohne?

Ich würd das dann so machen, dass dein objekt lediglich eine beziehung zur deiner liste hast. Beim einfügen in die liste wird im objekt ein observer registriert, sodass die die liste benachrichtigt wird, sobald sich das objekt zerstört. Wird das objekt normal aus der liste entfernt, so kann es den der observer auch wieder aus dem objekt entfernt werden.

Jedes objekt kann jetzt soviele listen haben wie es will, da die listen die beziehungen managen. Ein objekt kann dan auch in vielen listen sein, denn wenn es sich ändert (zB. zerstört) dann werden alle listen benachrichtigt, in denen es enthalten ist. Wenn sich eine liste zerstört, so wird der observer entfernt, sodass sie nicht mehr benachrichtig wird. Alle listen haben immer ihr objekt als owner, sodass sie evtl. benachritigungen an ihn weiter geben können.

Die benachrichtigungen würd ich sehr allgemein halten (notify-basis-klasse), sodass nicht nur auf zerstörung, sondern auch auf andere änderungen reagiert werden kann.

Bleibt nur noch das problem mit den besitzverhältnissen. Evtl. macht es sinn, geweils einer list eine besondere bedeutung zu geben -> Child/owner liste! Evtl kann man hier eine ListenKlasse ableiten, die beim einfügen sich selbst als Owner im objekt setzt und wenn die liste zerstört wird, dann auch alle elemente zerstört.

:drunken:

...das sind jetzt nur meine ideen dazu. Das muss nicht so laufen. Gibt bestimmt noch andere wege/muster/techniken. Du könntest allerdings relativ schnell ein zyklisches problem kriegen, da sich die liste in den schwanz beissen können. Zumindest für den Child/owner baum solltest du zyklenfreiheit garantieren können :wink:


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:38 Uhr.
Seite 1 von 2  1 2      

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