delphi – how do anonymous methods work?

Question:

Example №1:

procedure TForm14.btn2Click(Sender: TObject);
var
  SomeObj: TmyObj;
begin
  SomeObj := TmyObj.Create;    // создаем объект
  try
    SomeObj.Text := 'asdfasdfasd';
    TThread.CreateAnonymousThread(
        procedure
      begin
        Sleep(1000);  // ожидаем, чтобы гарантированно завершился метод btn2Click
        TThread.Queue(nil,
            procedure
          begin
            ShowMessage(SomeObj.Text); // пытаемся показать сообщение
          end)
      end).Start;
  finally
    FreeAndNil(SomeObj); // высвобождаем объект до его показа через функции синхронизации.
  end;
end;

The method logically fails, because when the queue reaches ShowMessage, the object does not exist. If FreeAndNil replaced by Free , then an empty string is displayed in ShowMessage (well, let's say, it is logical – the object is destroyed, the memory that was allocated for its fields is returned to the "initial" state).

Example No. 2

procedure TForm14.btn3Click(Sender: TObject);
var
  Text: string;
begin
  Text := 'asdfasdf';
  TThread.CreateAnonymousThread(
    procedure
    begin
      Sleep(1000);
      TThread.Queue(nil,
          procedure
        begin
          ShowMessage(Text);
        end)
    end).Start;
  // выход из метода произойдет раньше, чем сработает ShowMessage
  // то есть - локальной переменной Text уже не будет
  // но всё отрабатывает!!!
  Text:='67563245';
end;

The text "67563245" is displayed. Why? After all, a string is essentially a pointer. And since it is a local variable, it should (and will) be released when the method exits (otherwise, memory leaks would go). Accordingly, de jure example No. 2 does not differ from example No. 1, but it is carried out …

The behavior with variables of other types (integer, for example) is completely consistent with what happens with string.


How does the compiler work with anonymous methods in Delphi? Interested at least – where and how the variables (including interfaces) used in the anonymous method are "pushed", since they successfully survive before the code of this anonymous method starts working?

Answer:

Parameters passed to the anonymous function are wrapped in an interface. In the first case, the reference to an object inside this interface does not know anything about the fact that the object has already been destroyed.

In the second case, when the string is saved, the count of references to the string will be increased and it will not be destroyed when the method exits. Therefore, everything works. The string will be destroyed when its reference count is zero.

Scroll to Top