![]() |
Verfügbarkeit von Objecten in unterschiedlichen Units
Hallo Zusammen,
ich bin mir nicht sicher, ob der Titel gut gewählt ist. Mir fehlen mal wieder ein paar Grundlagen und ich hoffe, Ihr helft mir weiter. Ich habe in einem Projekt eine Unit, die heißt TLogic_Procs. In dieser Unit habe ich eine Klasse (TLogic) und in der speichere ich verschiedene Proceduren und Functionen, die nicht projektspezifisch sind und die ich in anderen Projekten auch gut gebrauchen kann. Sieht vereinfacht so aus:
Delphi-Quellcode:
In dem Hauptfenster des Projectes, wo die TLogic_Procs in den uses steht, setze ich im FormShowEvent:
type
TWriteServerActivities = procedure (Memo_Name: string; Activity: string) of Object; TWriteMailLog = procedure (SG_Name: string; Date, Betreff, LSchein, Empfaenger, Attachm, Result: string) of Object; TRows = array of array of string; // [Cols, Rows] TCols = array of string; TLogic = class strict protected private fWriteServerActivities: TWriteServerActivities; fWriteMailActivities: TWriteServerActivities; fWriteMailLog: TWriteMailLog; //Viele Proceduren public //Viele Proceduren constructor Create(SActivities: TWriteServerActivities = nil; MLog: TWriteMailLog = nil); end; var Logic_Main: TLogic; implementation constructor TLogic.Create(SActivities: TWriteServerActivities = nil; MLog: TWriteMailLog = nil); begin if assigned(SActivities) then begin fWriteServerActivities:= SActivities; end; if assigned(MLog) then begin fWriteMailLog:= MLog; end; end; Initialization Logic_Main := TLogic.Create; Finalization Logic_Main.Free;
Delphi-Quellcode:
Die Write-Procedure führen dann in dem Hauptfenster Protokoll-Aufgaben durch. Das klappt auch wunderbar, um ehrlich zu sein, besser als ist verstehen kann. Denn nun zu meiner Frage:
procedure TMainForm.FormShow(Sender: TObject);
var I: integer; begin Logic_Main.WriteServerActivities:= Write_ServerAcitities; Logic_Main.WriteMailActivities:= Write_ServerAcitities; Logic_Main.WriteMailLog:= Write_MailLog; end; Da ich mit mehreren Threads arbeite, erstelle ich oft in Procedure ein neues Object: TLogic (ich gebe es am Ende auch wieder frei). Und egal wo ich bin (die Units haben oft keine Verlinkung untereinander, die TLogic_Procs steht auch dort in den uses), ich kann immer auf Logic_Main zugreifen. Konkret heiß das, dass ich in der TLogic.Create(Logic_Main.WriteServerActivities) verwenden kann und die Procedure, die ich beim Programmstart der automatisch erstellten Logic_Main Variable zugeordnet habe, wird ausgeführt. So möchte ich es auch gerne haben, aber ich verstehe ehrlich gesagt nicht, warum das sehr zuverlässig funktioniert. Ich habe immer gedacht, dass wenn eine Unit in den uses steht, dass sie dann wieder neu created wird, aber warum steht dann die Procedure aus dem Hauptfenster zur Verfügung. Hintergrund ist, dass ich gerade an einer Klasse bastle, bei der ich auch Daten aus einem zentralen Object in neu angelegte Objecte (und zurück) übergeben möchte. Und da möchte ich es gerne "richtig" machen... Meine Theorie ist, dass das Object Logic_Main einen Pointer bekommt und dass wenn die Unit TLogic_Procs in einer anderen Unit in den uses steht, sie zwar neu wieder erstellte wird, aber dass das "neue" Object Logic_Main wieder den gleichen Pointer erhält und somit das "gleiche" Object ist. Aber das ist nur eine Theorie... Könnt Ihr mir hier Klarheit verschaffen? Vielen Dank Patrick |
AW: Verfügbarkeit von Objecten in unterschiedlichen Units
Zitat:
Es werden lediglich beim Starten der Anwendung die initialization und beim Beenden die finalization Sektion ganz unten in der Unit ausgeführt, ebenso wie Klassenkonstruktoren und -destruktoren. Dabei werden immer zuerst die Units in der uses initialisiert und dann die Unit selbst. Das ist der Grund, dass das so funktioniert. Die Funktionen aus dem Hauptfenster weist du ja selbst von außen zu. Wo die deklariert sind, weiß die Unit gar nicht. Die bekommt nur die Adresse und kann sie so aufrufen. |
AW: Verfügbarkeit von Objecten in unterschiedlichen Units
Zitat:
|
AW: Verfügbarkeit von Objecten in unterschiedlichen Units
So habe ich das bei mir gelöst:
Delphi-Quellcode:
Keine Ahnung, ob das der beste Weg ist, aber beim Initialisieren der Unit wird FMeinObjekt explizit ungültig gemacht (NIL), dass es nicht auf irgendeinen zufälligen Arbeitsspeicherbereich verweist, und dieser dann versehentlich als FMeinObjekt behandelt wird.
type
TMeinObjekt = class(TComponent) ... function MeinObjekt: TMeinObjekt; implementation var // Edit: Danke für den Hinweis! FMeinObjekt: TMeinObjekt = NIL; function MeinObjekt: TMeinObjekt; begin Result := NIL; try if not assigned(FMeinObjekt) then begin FMeinObjekt := TMeinObjekt.Create(NIL); end; Result := FMeinObjekt; except on E: SysUtils.Exception do begin ... end; end; end; ... initialization begin // In der Tat unnötig FMeinObjekt:= NIL; end; finalization FreeAndNil(FMeinObjekt); Die function MeinObjekt: TMeinObjekt; sorgt dafür, dass du immer ein gültiges Objekt erhältst, und dass es (über diesen Weg) auch immer nur eine Instanz gibt. Wird das Programm beendet, wird das Objekt im Finalization-Abschnitt korrekt freigegeben. Benötigt ein anderes Programm dieses Objekt nicht, wird es nicht erzeugt. Wird es benötigt, wird es automatisch erzeugt. Wird es erzeugt, wird es automatisch freigegeben. Du darfst/solltest halt an keiner anderen Stelle im Quellcode weitere Instanzen davon erzeugen mit TMeinObjekt.Create, ansonsten sollte alles passen? ![]() |
AW: Verfügbarkeit von Objecten in unterschiedlichen Units
Guten Morgen Zusammen,
vielen Dank für Eure Antworten und Erklärungen! @jaenicke und @Medium Ich habe mich falsch ausgedrückt, ich meinte nicht, dass create ausgeführt wird, sondern der Initialzation-Teil. Aber ich habe Euch verstanden, dass der nur ausgeführt wird, wenn die App gestartet wird und nichts mit der Benennung in des uses zu tun hat. Und da ich in der TLogic ja in der Initialization Logic:Main:= TLogic.Create verwende, steht Logic_Main der App zur Verfügung. Das eigentlich interessante ist, dass Logic_Main in der TLogic_Procs erstellt wird und dass ich auf dieses Object von jeder Unit aus zugreifen kann, in der TLogic_Procs in den uses steht. Das erklärt, warum es funktioniert und eröffnet mir ganz neue Möglichkeiten. @berens Vielen Dank für das Bespiel. Ich denke aber, dass ich es für dieses Object nicht verwenden kann. Ich verwende in vielen Procedure und Funktionen ein Object von TLogic und ich habe mir angewöhnt, immer ein solches zu createn und im Finally-Teil wieder freizugeben. Damit kann ich Proceduren und Funktionen auch in Threads einsetzen, ohne das es knallt. Aber für andere Objecte könnte das sehr interessant sein. Vielen Dank und habt einen guten Tag Patrick |
AW: Verfügbarkeit von Objecten in unterschiedlichen Units
Zitat:
Hier wird kein Create durchgeführt sondern ein Nil Pointer auf ein Objekt gesetzt, dass es eigentlich noch nicht geben dürfte. Es sei den, du erzeugst das Objekt direkt beim Programmstart (Quelltext des Projekts selbst und nicht in der Unit). Selbst dann müsste es aber "leer" sein. |
AW: Verfügbarkeit von Objecten in unterschiedlichen Units
Zitat:
Delphi-Quellcode:
https://www.youtube.com/watch?v=I15UFEIfSao
|
AW: Verfügbarkeit von Objecten in unterschiedlichen Units
Zitat:
tja, ich leide an Fehler-Paranoia :lol: Tatsache ist, das es für mich sehr "diffus" ist, wann/ob Delphi Variablen richtig initialisiert. Der Arbeitsspeicher (RAM) deines Computers wird ja wiederverwendet: Wenn du ein Programm zumachst, wir der Arbeitsspeicher frei, in dem Sinne von "Keine Referenz zeigt mehr darauf", aber der RAM wird -meines Wissens(!) nicht "Formatiert", so dass nach Programmende der komplette Arbeitsspeicher auf 0000000 steht, sondern es bleibt zunächst mal alles so wie es gerade ist. Wenn du nun in Delphi neue Variablen und Objekte hast, die einen Zeiger auf den Arbeitsspeicher bekommen mit "den darfst du benutzen, da arbeitet aktuell niemand mit", bedeutet das nicht, dass nun der komplette Arbeitsspeicher auf 0 gesetzt wird, sondern dass dort immernoch ein Buchstabensalat stehen *könnte*, und somit in einer brandneuen, uninitialisierten integer Variable der Wert 17 steht, in einem String "adfkgjzudfdui", und in bei einem Zeiger auf ein Objekt dieses bei Assigned(MeinObjekt)=True zurück geben könnte. Wie gesagt, das ist nur die Paranoia. In der Delphi Hilfe finde ich bei den einzelnen Datentypen (Integer, TComponent, String, ...) NICHT, *ob* die Variablen immer initilaisiert werden (string='' integer=0 TMeinObjekt=NIL) und wenn ja, mit welchem Wert. Damit ich nicht böse überrascht werde, oder in einer neuen Delphi Version auf einmal alles gehandhabt wird (Hey, deine widestring-variable ist nun beim Programmstart nicht mehr '' sonder NIL!) initialisiere ich lieber 100x unnötig alles per Hand, kann dann aber sicher sein, dass alles wirklich so ist, wie erwartet. Also: Ja, beim Programmstart wird die MeinObjekt (unnötig) auf NIL gesetzt - damit stelle ich sicher, dass assigned() in der entsprechenden Methode auch wirklich 100% sicher sagen kann, ob das Objekt *gültig* existiert, oder nicht. Wie gesagt, assigned(MeinObjekt) könnte(?) evtl. true bei sein, obwohl ich noch kein Objekt erzeugt habe. Die Funktion erzeugt dann das gültige Objekt und gibt es zurück. Ja, wahrscheinlich alles komplett übertrieben und unnötig, aber ich habe mit Delphi einfach schon viel zu viel Bulls*** erlebt, als dass mich sowas noch wundern würde. Zeigt mir gerne wo steht, dass *ALLE* Variablen und Objekte stets mit 100% Zuverlässigkeit mit NIL, 0 oder "" initialisiert werden. --> Danke für den Link, ich hatte bei "Integer" und "Einfache Typen" gesucht, aber bei "Variablen" war zu einfach :lol:. Tatsächlich trifft das aber dennoch nur auf globale, nicht auf lokale Variablen zu. ChatGPT sagt dazu: Zitat:
Okay, also globale Variablen und Objekte scheinen das Problem nicht zuhaben, lokale schon. Was soll das denn bitte? Gut, mein initialisieren ist unnötig, aber ich kotze im Strahl mit den 1000 Sonderfällen und Ausnahmeregelungen in Delphi wann was geht oder nicht geht, oder wann was automatisch passier und wann nicht. So ist es mehr Tipp-Arbeit und unnötig, aber zumindest ist damit meine Speicherverwaltung konsistent für lokale und globale Variablen. :stupid: Ich hätte Schreiner werden sollen... :roll: |
AW: Verfügbarkeit von Objecten in unterschiedlichen Units
Man kann globale Variablen auch gleich bei der Deklaration initialisieren:
Delphi-Quellcode:
var
FMeinObjekt: TMeinObjekt = nil; |
AW: Verfügbarkeit von Objecten in unterschiedlichen Units
Zitat:
![]() Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:19 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