Weist Delphi die Variable zu, bevor das Objekt erstellt wird?

Weist Delphi eine Instanzvariable zu, bevor das Objekt vollständig erstellt ist?

Mit anderen Worten, eine Variable gegeben:

var
   customer: TCustomer = nil; 

Wir konstruieren dann einen Kunden und weisen ihn der Variablen zu:

customer := TCustomer.Create;

Ist es möglich dasscustomer kann nicht seinnil, aber nicht auf einen fertig konstruierten zeigenTCustomer?

Dies wird zu einem Problem bei der Durchführung einer verzögerten Initialisierung:

function SacrifialCustomer: TCustomer;
begin
   if (customer = nil) then
   begin
      criticalSection.Enter;
      try
         customer := TCustomer.Create;
      finally 
         criticalSection.Leave;
      end;
   end;
   Result := customer;
end;

Der Fehler ist in der Zeile:

if (customer = nil) 

Möglicherweise ruft ein anderer Thread Folgendes auf:

customer := TCustomer.Create;

und der Variablen wird ein Wert zugewiesen, bevor die Konstruktion erfolgt. Dies bewirkt, dass der Thread zuannehmen Dascustomer ist ein gültiges Objekt, nur weil die Variable zugewiesen ist.

Kann dieser Singleton-Fehler mit mehreren Threads in Delphi (5) auftreten?

Bonus-Frage

Gibt es eine akzeptierte, thread-safe,einmalige Initialisierung Entwurfsmuster für Delphi? Viele Leute haben umgesetztSingletons in Delphi durch ÜberschreibenNewInstance undFreeInstance; Ihre Implementierungen schlagen in mehreren Threads fehl.

Genau genommen bin ich nicht hinter einer Antwort zurück, wie und zu implementieren istSingleton, aberLazy-Initialisierung. WährendSingletons könnenbenutzen Lazy-Initialisierung,Lazy Initialisierung ist nicht auf Singletons beschränkt.

Aktualisieren

Zwei Leute schlugen eine Antwort vordas enthält einen häufigen Fehler. Dasfehlerhafter doppelt überprüfter Sperralgorithmus in Delphi übersetzt:

// Broken multithreaded version
// "Double-Checked Locking" idiom
if (customer = nil) then
begin
   criticalSection.Enter;
   try
      if (customer = nil) then
         customer := TCustomer.Create;
   finally
      criticalSection.Leave;
   end;
end;
Result := customer;

VonWikipedia:

Intuitiv scheint dieser Algorithmus eine effiziente Lösung des Problems zu sein. Diese Technik weist jedoch viele subtile Probleme auf und sollte normalerweise vermieden werden.

Ein weiterer Vorschlag für einen Buggy:

function SacrificialCustomer: TCustomer;
var
  tempCustomer: TCustomer;
begin
   tempCustomer = customer;
   if (tempCustomer = nil) then
   begin
      criticalSection.Enter;
      try
         if (customer = nil) then
         begin
            tempCustomer := TCustomer.Create;
            customer := tempCustomer;
         end;
      finally
         criticalSection.Leave;
      end;
   end;
   Result := customer;
end;

Aktualisieren

Ich habe Code erstellt und mir das CPU-Fenster angesehen. Es scheint, dass dieser Compiler mit meinen Optimierungseinstellungen unter dieser Windows-Version mit diesem Objekt zuerst das Objekt erstellt.dann weist die Variable zu:

customer := TCustomer.Create;
       mov dl,$01
       mov eax,[$0059d704]
       call TCustomer.Create
       mov [customer],eax;
Result := customer;
       mov eax,[customer];

Natürlich kann ich nicht sagen, dass das garantiert immer so funktioniert.

Antworten auf die Frage(4)

Ihre Antwort auf die Frage