¿Delphi asigna la variable antes de que se construya el objeto?

¿Delphi asigna una variable de instancia antes de que el objeto esté completamente construido?

En otras palabras, dada una variable:

var
   customer: TCustomer = nil; 

luego construimos un cliente y lo asignamos a la variable:

customer := TCustomer.Create;

Es posible quecustomer puede no sernil, pero no apuntan a una totalmente construidaTCustomer?

Esto se convierte en un problema al realizar la inicialización perezosa:

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

El error está en la línea:

if (customer = nil) 

Es posible que otro hilo llame:

customer := TCustomer.Create;

y a la variable se le asigna un valor antes de que ocurra la construcción.. Esto hace que el hiloasumir esecustomer es un objeto válido simplemente porque la variable está asignada.

¿Puede suceder este error de singleton multihilo en Delphi (5)?

Pregunta extra

¿Hay una aceptada, segura de hilo,inicialización única patrón de diseño para Delphi? Muchas personas han implementadosingletons en Delfos anulandoNewInstance yFreeInstance; Sus implementaciones fallarán en múltiples hilos.

Hablando estrictamente, no busco una respuesta sobre cómo implementar ysemifallo, peroinicialización perezosa. Mientrassingletons puedeutilizar inicialización perezosa,inicialización perezosa no se limita a singletons.

Actualizar

Dos personas sugirieron una respuesta.que contiene un error común losalgoritmo de bloqueo de doble comprobación roto traducido a Delphi:

// 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;

DesdeWikipedia:

Intuitivamente, este algoritmo parece una solución eficiente al problema. Sin embargo, esta técnica tiene muchos problemas sutiles y, por lo general, debe evitarse.

Otra sugerencia de 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;

Actualizar

Creé algo de código y miré la ventana de la CPU. Parece que este compilador, con mi configuración de optimización, en esta versión de Windows, con este objeto, construye primero el objeto,entonces Asigna la variable:

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

Por supuesto, no puedo decir que eso garantice que siempre funcione de esa manera.

Respuestas a la pregunta(4)

Su respuesta a la pregunta