Этот вопрос является продолжением конкретного комментария от людей о stackoverflow, который я видел несколько раз. Я, вместе с разработчиком, который научил меня Delphi, чтобы все было в безопасности, всегда ставил чек if assigned()
перед освобождением объектов и перед другими делами. Тем не менее, теперь мне говорят, что я не должен добавлять эту проверку. Я хотел бы знать, есть ли какая-либо разница в том, как приложение компилируется/запускается, если я это сделаю, или если оно вообще не повлияет на результат...
if assigned(SomeObject) then SomeObject.Free;
Скажем, у меня есть форма, и я создаю объект растрового изображения в фоновом режиме при создании формы и освобождая его, когда я закончил с ним. Теперь я думаю, что моя проблема заключается в том, что я слишком привык ставить эту проверку на свой код, когда пытаюсь получить доступ к объектам, которые потенциально могли быть свободными в какой-то момент. Я использовал его, даже если это не нужно. Мне нравится быть основательным...
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FBitmap: TBitmap;
public
function LoadBitmap(const Filename: String): Bool;
property Bitmap: TBitmap read FBitmap;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
FBitmap:= TBitmap.Create;
LoadBitmap('C:\Some Sample Bitmap.bmp');
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
if assigned(FBitmap) then begin //<-----
//Do some routine to close file
FBitmap.Free;
end;
end;
function TForm1.LoadBitmap(const Filename: String): Bool;
var
EM: String;
function CheckFile: Bool;
begin
Result:= False;
//Check validity of file, return True if valid bitmap, etc.
end;
begin
Result:= False;
EM:= '';
if assigned(FBitmap) then begin //<-----
if FileExists(Filename) then begin
if CheckFile then begin
try
FBitmap.LoadFromFile(Filename);
except
on e: exception do begin
EM:= EM + 'Failure loading bitmap: ' + e.Message + #10;
end;
end;
end else begin
EM:= EM + 'Specified file is not a valid bitmap.' + #10;
end;
end else begin
EM:= EM + 'Specified filename does not exist.' + #10;
end;
end else begin
EM:= EM + 'Bitmap object is not assigned.' + #10;
end;
if EM <> '' then begin
raise Exception.Create('Failed to load bitmap: ' + #10 + EM);
end;
end;
end.
Теперь скажем, что я представляю новый пользовательский объект списка TMyList
из TMyListItem
. Для каждого элемента в этом списке, конечно, мне нужно создать/бесплатно каждый объект объекта. Существует несколько различных способов создания элемента, а также несколько различных способов уничтожения элемента (добавление/удаление является наиболее распространенным). Я уверен, что это очень хорошая практика, чтобы поставить эту защиту здесь...
procedure TMyList.Delete(const Index: Integer);
var
I: TMyListItem;
begin
if (Index >= 0) and (Index < FItems.Count) then begin
I:= TMyListItem(FItems.Objects[Index]);
if assigned(I) then begin //<-----
if I <> nil then begin
I.DoSomethingBeforeFreeing('Some Param');
I.Free;
end;
end;
FItems.Delete(Index);
end else begin
raise Exception.Create('My object index out of bounds ('+IntToStr(Index)+')');
end;
end;
Во многих сценариях, по крайней мере, я надеюсь, что объект все еще будет создан, прежде чем я попытаюсь его освободить. Но вы никогда не знаете, какие промахи могут произойти в будущем, когда объект освобождается до того, как он это предположил. Я всегда пользовался этой проверкой, но теперь мне говорят, что я не должен, и я до сих пор не понимаю, почему.
ИЗМЕНИТЬ
Вот пример, чтобы попытаться объяснить вам, почему у меня есть привычка делать это:
procedure TForm1.FormDestroy(Sender: TObject);
begin
SomeCreatedObject.Free;
if SomeCreatedObject = nil then
ShowMessage('Object is nil')
else
ShowMessage('Object is not nil');
end;
Моя точка зрения заключается в том, что if SomeCreatedObject <> nil
не совпадает с if Assigned(SomeCreatedObject)
, потому что после освобождения SomeCreatedObject
он не оценивает значение nil
. Поэтому должны быть необходимы обе проверки.