Делает ли Delphi переменную перед созданием объекта?

Делает ли Delphi переменную экземпляра до полного создания объекта?

Другими словами, учитывая переменную:

var
   customer: TCustomer = nil; 

Затем мы создаем клиента и присваиваем его переменной:

customer := TCustomer.Create;

Возможно ли, чтоcustomer может быть неnil, но не указывают на полностью построенныйTCustomer?

Это становится проблемой при выполнении отложенной инициализации:

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

Ошибка в строке:

if (customer = nil) 

Возможно, что другой поток вызывает:

customer := TCustomer.Create;

и переменной присваивается значение до начала строительства, Это заставляет потокassume тотcustomer является допустимым объектом просто потому, что переменная назначена.

Может ли эта многопоточная ошибка синглтона произойти в Delphi (5)?

Bonus Question

Есть ли принятый, потокобезопасный,однократная инициализация шаблон дизайна для Delphi? Многие люди реализовалиsingletons в Delphi путем переопределенияNewInstance а такжеFreeInstance; их реализации потерпят неудачу в нескольких потоках.

Строго говоря, я не после ответа о том, как реализовать иsingleton, ноlazy-initialization, В то время какsingletons Можноuse ленивая инициализация,lazy initialization не ограничивается одиночками.

Update

Два человека предложили ответэто содержит распространенную ошибку.broken double-checked locking algorithm translated to 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;

ОтВикипедия:

Intuitively, this algorithm seems like an efficient solution to the problem. However, this technique has many subtle problems and should usually be avoided.

Еще одно ошибочное предложение:

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;

Update

Я создал некоторый код и посмотрел на окно процессора. Кажется, что этот компилятор с моими настройками оптимизации в этой версии Windows, с этим объектом, сначала создает объект,then назначает переменную:

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

Конечно, я не могу сказать, что это всегда гарантировано.

Ответы на вопрос(4)

Ваш ответ на вопрос