![]() |
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:
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.
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; 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 |
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; |
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:
die Prüfung machen.
if Self=nil then
3. Entfällt 2 dann, weil du Free direkt aufrufen kannst, wenn du deiner Funktion einen anderen Namen gibts. |
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.
![]() (oder du hast einfach nur einen Fehler beim Abschreiben gemacht) |
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:
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!)
procedure TMyList.Free(ADoSomething: boolean);
begin if Self <> nil then begin FDoSomething := ADoSomething; inherited Free; end; end; 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! |
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. |
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:... |
Re: Methode "Free" selbst implementieren (Assemble
Aber warum willst du eigentlich ein eigenes Free ? :gruebel:
|
Re: Methode "Free" selbst implementieren (Assemble
@Neutral General
Zitat:
@sakura Zitat:
|
Re: Methode "Free" selbst implementieren (Assemble
Folgende "einfache" Lösung ist auch möglich.
Delphi-Quellcode:
Dann kannst Du einfach mit folgenden Zeilen Deinen Zweck erfüllen.
TMyList = class(TList)
public DoSomething : boolean; destructor Destroy; override; end; destructor TMyList.Destroy; begin if DoSomething then begin ...do something... end; inherited; end;
Delphi-Quellcode:
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.
...
var ml : TMyList; ... begin ... ml := TMyList.Create; ... ml.DoSomething := True; ... ml.Free; ml := Nil; ... end; ... |
Re: Methode "Free" selbst implementieren (Assemble
Zitat:
...:cat:... |
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.
|
Re: Methode "Free" selbst implementieren (Assemble
Zitat:
|
Re: Methode "Free" selbst implementieren (Assemble
Zitat:
|
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..
|
Re: Methode "Free" selbst implementieren (Assemble
Zitat:
|
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:
|
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; |
Re: Methode "Free" selbst implementieren (Assemble
Zitat:
|
Re: Methode "Free" selbst implementieren (Assemble
Zitat:
|
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; |
Re: Methode "Free" selbst implementieren (Assemble
Folgendes "einfaches" Beispiel sollte Dein Problem lösen:
Unit1.pas
Delphi-Quellcode:
Hier werden 3 wichtige Dinge implementiert:
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.
Delphi-Quellcode:
Die Unit 2 ist ein leeres TForm mit 7 TButtons
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.
Das Ganze wird in die Project1.dpr eingebunden:
Delphi-Quellcode:
Viel Spaß
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. [edit] wichtig: Es muß natürlich erst der Button1 gedrückt werden, damit TMyObject.Create aufgerufen wird. ;-) [/edit] |
Re: Methode "Free" selbst implementieren (Assemble
Zitat:
|
Re: Methode "Free" selbst implementieren (Assemble
Zitat:
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. |
Re: Methode "Free" selbst implementieren (Assemble
Zitat:
|
Re: Methode "Free" selbst implementieren (Assemble
Zitat:
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? |
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.
|
Re: Methode "Free" selbst implementieren (Assemble
Zitat:
|
Re: Methode "Free" selbst implementieren (Assemble
Zitat:
|
Re: Methode "Free" selbst implementieren (Assemble
Zitat:
|
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? |
Re: Methode "Free" selbst implementieren (Assemble
Zitat:
An sonsten hört sich das vernünftig an :) |
Re: Methode "Free" selbst implementieren (Assemble
Zitat:
|
Re: Methode "Free" selbst implementieren (Assemble
Zitat:
Delphi-Quellcode:
oder so. Frage mich wo das problem liegt. Allerdings kenne ich deine implementierung auch nicht.
procedure liste.fügehinzu(element)
begin TuInListe(element); if element.besitzer = nil then element.besitzer = mirSelbst; end; |
Re: Methode "Free" selbst implementieren (Assemble
Zitat:
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. |
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:
Delphi-Quellcode:
...nur das auf die prüfung verzichtet wird.
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; 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: |
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. |
Re: Methode "Free" selbst implementieren (Assemble
Mit anderen worten: Du willst eine baum-komposition (Kompositum) realisieren ->
![]() 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 ![]() 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: |
Re: Methode "Free" selbst implementieren (Assemble
Zitat:
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. |
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. |
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