Это ошибка, чтобы освободить форму, в которой MainForm является владельцем?

В нашем существующем коде у нас есть куча, где форма создается с помощью MainForm как владелец (скажем, вместо nil), но мы освобождаем его явно.

function SomeFunc(): Boolean;
var
  form: TMyForm; // subclasses TForm
begin
  with TMyForm.Create(Application.MainForm) do
    try
      ShowModal;
      Exit(True);
    finally
      Free;
    end
end;

Может ли это вызвать любую ошибку или ошибку или это безопасно?

Я не могу разобраться, прочитав документ:

http://docwiki.embarcadero.com/Libraries/Berlin/en/System.Classes.TComponent.Owner

http://docwiki.embarcadero.com/Libraries/Berlin/en/System.Classes.TComponent.Create

delphi,delphi-10.1-berlin,

5

Ответов: 3


Посмотрите на исходный код, и вы сами можете ответить на этот вопрос!

TForm наследует вдалеке от TComponent, если мы посмотрим на деструктор TComponent, мы увидим это (по крайней мере, в DelphiXE7):

destructor TComponent.Destroy;
begin
  Destroying;
  RemoveFreeNotifications;
  DestroyComponents;
  if FOwner <> nil then FOwner.RemoveComponent(Self);
  FObservers.Free;
  inherited Destroy;
end;

Здесь есть две важные линии:

  • DestroyComponents

Это уничтожит все принадлежащие ему компоненты при уничтожении, прежде чем сам владелец будет уничтожен.

  • if FOwner <> nil then FOwner.RemoveComponent(Self);

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

поэтому в вашем случае Application.MainForm будет принадлежать вашему экземпляру TMyForm, но при уничтожении он исчезнет из списка компонентов основной формы.

Короче говоря, ваш код отлично подходит и не будет разбиваться. Но чтобы было ясно, что вы управляете жизненным циклом компонента, вы должны передать nil как Owner в конструкторе. И поскольку Sertac Akyuz уже упомянул в комментариях, вы избежите вызова, FOwner.RemoveComponent(Self);который будет экономить некоторые циклы процессора ...


2

Это не ошибка, но это, безусловно, запах кода. Предпочтительный способ сделать это (цикл создания-шоу-уничтожения модальной формы):

  function SomeFunc(): Boolean;
  var
    form: TMyForm;
  begin
    form := TMyForm.Create(nil);
    try
      Result := form.ShowModal = mrOk; // this can vary, of course
    finally
      form.Release;
    end
  end;

Обратите внимание, что я не звоню напрямую с TForm.Free . Вместо этого я вызываю метод TForm.Release, который безопаснее. Из файла справки RAD Studio:

Release не уничтожает форму до тех пор, пока все обработчики событий формы и обработчики событий компонентов в форме не закончатся. Release также гарантирует, что все сообщения в очереди событий формы будут обработаны до того, как форма будет выпущена. Любые обработчики событий для формы или ее дочерних элементов должны использовать Release вместо Free (Delphi) или delete (C ++). Несоблюдение этого требования может привести к ошибке доступа к памяти.


1

Насколько я знаю, это совершенно безопасно, если вы гарантируете, что ваша основная форма не будет освобождена, пока будет показана ваша дочерняя форма, которая станет беспорядочной. Я ожидал бы «нарушение прав доступа» или «Неверная операция указателя» в ChildForm.Free, то есть, если он делает это так далеко.

В небольшом тестовом случае приложение фактически оставалось в мутационном цикле (теперь уничтоженной) второй формы.

Но так как освобождение основной формы - это работа, лучше оставляемая для TApplication, я думаю, что мы можем заключить, используя основную форму, поскольку владелец вашей дочерней формы отлично работает.

Что касается аспекта управления жизненным циклом вопроса, см. Ответ whosrdaddy.

дельфин, дельфин-10,1-берлин,
Похожие вопросы