Как я могу установить внешнюю переменную на ноль внутри метода?

Я хотел бы подкласс TThread для того, чтобы иметь класс потока, который, когда FreeOnTerminate = Trueустанавливает nil его ссылочная переменная. Другими словами, я хочу сделать что-то вроде этого:

TFreeAndNilThread = class(TThread)
private
  FReferenceObj: TFreeAndNilThread;  //??  // <-- here I'm holding the reference to myself
protected
  procedure Execute;
  procedure DoTerminate; override;  // <-- here I'll set FReferenceObj to nil after inherited (only if FreeAndNil = True)
public
  constructor Create(CreateSuspended: Boolean; var ReferenceObj); reintroduce;  <-- untyped param like FreeAndNil and TApplication.CreateForm ??
end;

Код потребителя должен быть таким:

var
  MyThread: TFreeAndNilThread;

begin
  MyThread := TFreeAndNilThread.Create(True, MyThread);
  MyThread.FreeOnTerminate := True;
  MyThread.Resume;
end;

... и тогда я смог бы безопасно проверить Assigned(MyThread),

Я вижу как FreeAndNil удается установить ссылочный объект, переданный нетипизированным параметром nil, но это делает это локально. В моем случае я должен "сохранить" его в поле класса (FReferenceObj) и сделать это ноль в другом месте (DoTerminate).

Как я могу правильно передать, сохранить и получить его? Я могу думать о передаче и сохранении адреса MyThread вместо самого MyThread, но я надеюсь, что есть более элегантный способ.

Спасибо!

1 ответ

Решение

Вам нужно сохранить указатель на переменную.

type
  TFreeAndNilThread = class(TThread)
  private
    FReferenceObj: ^TFreeAndNilThread;
  end;

Затем вам нужно передать ссылку в конструкторе:

type
  TFreeAndNilThread = class(TThread)
  private
    FReferenceObj: ^TFreeAndNilThread;
  public
    constructor Create(var ReferenceObj: TFreeAndNilThread);
  end;

Тогда вы можете реализовать это так:

constructor TFreeAndNilThread.Create(var ReferenceObj: TFreeAndNilThread);
begin
  inherited Create(True);
  FreeOnTerminate := True;
  FReferenceObj := @ReferenceObj;
end;

Когда поток умирает, вы устанавливаете ссылку на nil как это:

ReferenceObj^ := nil;

Для удобства, поскольку вы, скорее всего, будете рассматривать это как базовый класс, из которого вы производите другие классы, вы можете предпочесть сделать параметр для конструктора нетипизированным. Вы можете просто сделать это без внесения других изменений в код. Когда вы это делаете, конструктор выглядит так:

constructor Create(var ReferenceObj);

Это пойдет вам на пользу, только если код, который устанавливает ссылку на nil находится в том же потоке, что и весь другой код, который пытается ссылаться MyThread, В противном случае у вас будет состояние гонки.

Я вполне уверен, что ваша идея не является решением вашей проблемы. Однако вышеприведенное показывает, как получить ссылку на переменную, о чем вы просили.

Другие вопросы по тегам