Подтвердить что ты не робот

Каков правильный способ динамического создания/выпуска форм времени выполнения?

Я всегда стараюсь создавать свои приложения с использованием памяти, если вам это не нужно, тогда не создавайте, так как я смотрю на него.

В любом случае, возьмите в качестве примера следующее:

Form2:= TForm2.Create(nil);
try
  Form2.ShowModal;
finally
  Form2.FreeOnRelease;
end;

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

В чем разница между вызовами:

Form2.Destroy;
Form2.Free;
Form2.FreeOnRelease;

Все они выполняют одно и то же или аналогичную работу, если я не пропущу что-то.

А также, когда следует использовать любой из вышеперечисленных? Очевидно, что при освобождении объекта я понимаю это, но в некоторых ситуациях Destroy лучше подходит, чем Free, например?

4b9b3361

Ответ 1

Форма2: = TForm2.Create(nil);

Это запах кода, потому что Form2 - это, вероятно, глобальная генерируемая IDE переменная, которая обычно содержит созданный IDE TForm2. Вы, скорее всего, хотите использовать локальную переменную и одну с лучшим именем. Это не обязательно ошибка, просто запах кода.

Form2.Destroy vs Form2.Free

Используйте Form2.Free, потому что он вызывает Destroy в любом случае. Вы можете CTRL + Click по имени (Free), чтобы увидеть его реализацию. По существу Free вызывает Destroy, если Self не равен нулю.

Form2.FreeOnRelease

Как сообщает документация, "It should not be necessary to call FreeOnRelease directly."

Ответ 2

Я никогда не слышал о FreeOnRelease раньше. Причина быстрого поиска Google. Из официальной документации:

FreeOnRelease вызывается, когда интерфейс, реализованный компонентом выпущен. Используется FreeOnRelease внутренне и вызывает соответствующие интерфейса. Так не должно быть необходимо позвонить FreeOnRelease непосредственно.

Что касается Free vs. Destroy, Free - это функция безопасности. Он в основном реализован как if self <> nil then self.Destroy;, и он был создан, чтобы сделать конструкторы и деструкторы безопасными для использования. Вот основная идея:

Если вы создаете объект и возникает необработанное исключение, деструктор вызывается. Если ваш объект содержит другие объекты, они могут быть или не созданы еще к моменту возникновения ошибки, поэтому вы не можете просто вызвать Destroy для всех из них. Но вам нужен способ убедиться, что те, которые были созданы, будут уничтожены.

Так как Delphi выдает адресное пространство объекта перед вызовом конструктора, все, что еще не было создано, в этот момент гарантировано nil. Таким образом, вы можете сказать if FSubObject <> nil then FSubObject.Destroy снова и снова для всех под-объектов (и если вы забудете, что получите доступ к нарушениям), или вы можете использовать метод Free, который сделает это за вас. (Это огромное улучшение по сравнению с С++, где пространство памяти не обнуляется перед вызовом конструктора, что требует, чтобы вы обернули все ваши под-объекты в интеллектуальные указатели и использовали RAII для обеспечения безопасности исключений!)

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

Сказав, что, когда речь идет о формах, есть дополнительная переменная, которая учитывает уравнение: очередь сообщений Windows. Вы не знаете, есть ли еще ожидающие сообщения для формы, которую вы собираетесь освободить, поэтому не всегда безопасно вызывать Free в форме. Для этого существует метод Release. Он отправляет сообщение в очередь, которое заставляет форму освобождать себя, когда у нее больше нет сообщений для обработки, поэтому обычно это лучший способ освободить форму, которую вам больше не нужно.

Ответ 3

Каноническая форма:

Form := TMyForm.Create(nil);
try
  Form.ShowModal;
finally
  Form.Free;
end;

Никогда не вызывайте Destroy, всегда вызывайте Free.

FreeOnRelease - полная красная селедка. Иногда, если есть очереди сообщений, предназначенных для вашей формы или ее детей, вы можете выбрать Release, хотя часто это указывает на проблемы с дизайном.

Ответ 4

Идиоматическое использование

procedure SomeProc;
var
  frm: TForm2;
begin
  frm := TForm2.Create(nil);
  try
    frm.ShowModal;
  finally
    frm.Free;
  end;
end;

или, если вы не ненавидите конструкцию with,

with TForm2.Create(nil) do
  try
    ShowModal;
  finally
    Free;
  end;

Вы не должны называть Destroy, согласно документации. Фактически, Free в точности эквивалентен if Self <> nil then Destroy;. То есть, это "безопасная" версия Destroy. Он не падает полностью, если указатель оказывается nil. [Чтобы проверить это, добавьте личное поле FBitmap: TBitmap в класс формы, а затем OnCreate (например), попробуйте FBitmap.Free vs. FBitmap.Destroy.]

Если вы создаете форму, используя описанный выше подход, Free абсолютно безопасен, если вы не делаете какие-то странные вещи в классе формы.

Однако, если вы используете CreateForm(TForm2, Form2) для создания формы и сохранения объекта формы в глобальной переменной экземпляра Form2, и вы не сразу ее освободите [например, если вы хотите, чтобы окно придерживалось рядом с основная форма в немодальном режиме в течение нескольких минут], вы должны использовать Release вместо Free. Из документации,

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

FreeOnRelease не имеет ничего общего с формами. Из документов:

Не нужно звонить FreeOnRelease напрямую.