AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Verfügbarkeit von Objecten in unterschiedlichen Units
Thema durchsuchen
Ansicht
Themen-Optionen

Verfügbarkeit von Objecten in unterschiedlichen Units

Ein Thema von Ykcim · begonnen am 24. Feb 2025 · letzter Beitrag vom 25. Feb 2025
Antwort Antwort
Seite 1 von 2  1 2      
Ykcim

Registriert seit: 29. Dez 2006
Ort: NRW
856 Beiträge
 
Delphi 12 Athens
 
#1

Verfügbarkeit von Objecten in unterschiedlichen Units

  Alt 24. Feb 2025, 21:39
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:
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;
In dem Hauptfenster des Projectes, wo die TLogic_Procs in den uses steht, setze ich im FormShowEvent:
Delphi-Quellcode:
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;
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:
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
Patrick

Geändert von Ykcim (25. Feb 2025 um 08:41 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.845 Beiträge
 
Delphi 12 Athens
 
#2

AW: Verfügbarkeit von Objecten in unterschiedlichen Units

  Alt 24. Feb 2025, 22:25
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.
Die Unit ist lediglich ein Container. Der Eintrag in der uses heißt nur, dass du im Quelltext auf dort deklarierte Typen, Konstanten und Variablen zugreifen kannst, mehr nicht. Erzeugt wird dadurch nichts. Das ist nur die Zugriffsmöglichkeit.

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.
Sebastian Jänicke
AppCentral

Geändert von jaenicke (25. Feb 2025 um 02:57 Uhr)
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.687 Beiträge
 
Delphi 2007 Enterprise
 
#3

AW: Verfügbarkeit von Objecten in unterschiedlichen Units

  Alt 24. Feb 2025, 22:28
Ich habe immer gedacht, dass wenn eine Unit in den uses steht, dass sie dann wieder neu created wird
Das hier ist der Denkfehler. Mit "uses" gibst du nur an, dass du in der Unit in der du das "uses XYZ" hin schreibst, auf öffentliche Member von XYZ zugreifen möchtest. Diese sind identisch, egal von wo du letztlich drauf zugreifst. Da wird nichts neu erstellt; alles zeigt auf die selben Daten und Codestellen wie in XYZ direkt.
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
berens

Registriert seit: 3. Sep 2004
441 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: Verfügbarkeit von Objecten in unterschiedlichen Units

  Alt 25. Feb 2025, 00:30
So habe ich das bei mir gelöst:

Delphi-Quellcode:
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);
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.

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?

https://de.wikipedia.org/wiki/Singleton_(Entwurfsmuster)
Delphi 10.4 32-Bit auf Windows 10 Pro 64-Bit, ehem. Delphi 2010 32-Bit auf Windows 10 Pro 64-Bit

Geändert von berens (25. Feb 2025 um 11:35 Uhr)
  Mit Zitat antworten Zitat
Ykcim

Registriert seit: 29. Dez 2006
Ort: NRW
856 Beiträge
 
Delphi 12 Athens
 
#5

AW: Verfügbarkeit von Objecten in unterschiedlichen Units

  Alt 25. Feb 2025, 08:39
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
Patrick
  Mit Zitat antworten Zitat
fisipjm

Registriert seit: 28. Okt 2013
315 Beiträge
 
Delphi 12 Athens
 
#6

AW: Verfügbarkeit von Objecten in unterschiedlichen Units

  Alt 25. Feb 2025, 08:53
So habe ich das bei mir gelöst:

Delphi-Quellcode:
initialization
begin
  FMeinObjekt:= NIL;
end;

finalization
  FreeAndNil(FMeinObjekt);
Der initialization Teil ist in meinen Augen Sinnlos, korrigiert mich bitte wenn ich Falsch liege
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.
  Mit Zitat antworten Zitat
Hobbycoder

Registriert seit: 22. Feb 2017
998 Beiträge
 
#7

AW: Verfügbarkeit von Objecten in unterschiedlichen Units

  Alt 25. Feb 2025, 09:47
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
Vielleicht interessant für dich: https://www.youtube.com/watch?v=I15UFEIfSao
Gruß Hobbycoder
Alle sagten: "Das geht nicht.". Dann kam einer, der wusste das nicht, und hat's einfach gemacht.
  Mit Zitat antworten Zitat
berens

Registriert seit: 3. Sep 2004
441 Beiträge
 
Delphi 10.4 Sydney
 
#8

AW: Verfügbarkeit von Objecten in unterschiedlichen Units

  Alt 25. Feb 2025, 10:47
Der initialization Teil ist in meinen Augen Sinnlos, korrigiert mich bitte wenn ich Falsch liege
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.
Moin,
tja, ich leide an Fehler-Paranoia

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 . Tatsächlich trifft das aber dennoch nur auf globale, nicht auf lokale Variablen zu.

ChatGPT sagt dazu:
Zitat:
In Delphi werden globale Variablen und Felder von Objekten (also Klasseninstanzvariablen) automatisch mit nil initialisiert. Lokale Variablen, wie in deinem Beispiel die Variable b in der Prozedur, werden dagegen nicht automatisch auf nil gesetzt, wenn du sie nicht explizit initialisierst. Das bedeutet:

Globale Variablen und Klassenfelder: Immer nil, wenn sie noch keinen gültigen Wert erhalten haben.
Lokale Variablen (in Prozeduren/Funktionen): Können uninitialisiert sein und daher zufällige (Garbage‑)Werte enthalten, die nicht nil sind.

Die offizielle Embarcadero-Dokumentation zum Verhalten der Funktion Assigned und der Speicherinitialisierung bestätigt, dass nur Variablen, die explizit initialisiert wurden (oder als globale/Membervariablen deklariert sind), sicher den Wert nil besitzen. Wird eine lokale Variable nicht initialisiert, kann ein zufälliger Speicherwert vorliegen, wodurch Assigned(b) unter Umständen true zurückgeben kann.
Leider hat das der Link gefehlt.

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.

Ich hätte Schreiner werden sollen...
Delphi 10.4 32-Bit auf Windows 10 Pro 64-Bit, ehem. Delphi 2010 32-Bit auf Windows 10 Pro 64-Bit

Geändert von berens (25. Feb 2025 um 11:39 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.598 Beiträge
 
Delphi 12 Athens
 
#9

AW: Verfügbarkeit von Objecten in unterschiedlichen Units

  Alt 25. Feb 2025, 11:01
Man kann globale Variablen auch gleich bei der Deklaration initialisieren:
Delphi-Quellcode:
var
  FMeinObjekt: TMeinObjekt = nil;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.845 Beiträge
 
Delphi 12 Athens
 
#10

AW: Verfügbarkeit von Objecten in unterschiedlichen Units

  Alt 25. Feb 2025, 11:27
Zeigt mir gerne wo steht, dass *ALLE* Variablen und Objekte stets mit 100% Zuverlässigkeit mit NIL, 0 oder "" initialisiert werden.
Das ist eindeutig dokumentiert:
https://docwiki.embarcadero.com/RADS...ables_(Delphi)
Zitat:
If you do not explicitly initialize a global variable, the compiler initializes it to 0. Object instance data (fields) are also initialized to 0. On the Wiin32 platform, the contents of a local variable are undefined until a value is assigned to them.

When you declare a variable, you are allocating memory which is freed automatically when the variable is no longer used. In particular, local variables exist only until the program exits from the function or procedure in which they are declared.
Anders sieht es bei referenzgezählten Datentypen aus (strings, Interfaces, ...). Die werden auch lokal mit 0 initialisiert, was einfach daran liegt, dass ansonsten bei der ersten Zuweisung versucht würde, den alten Speicher freizugeben (obwohl der Wert gar nicht gültig wäre).
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 19:07 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 by Thomas Breitkreuz