1

I have sample code below can someone explain why delphi compiler not release all memory allocation for object so nil checking is always true. im using release method for destroying TLoginForm im not using free method because that gave me exception when some interfaced event called before free or after it.

type
  TMainForm = class(TForm)
  {some stuf}
  public
    procedure Create(AOwner: TComponent); override;
    procedure doLogout();
  end;

  TChildBase = class(TForm)
  {some stuf}
  public
    procedure Create(AOwner: TComponent); override;
  end;

  TLoginForm = class(TChildBase)
  public
    procedure doLogin();
  end;

var
  MainForm: TMainForm; {<== created automaticaly at runtime}
  LoginForm: TLoginForm; {<== created at create event in TMainForm}

implementation

{TLoginForm}
procedure TLoginForm.doLogin;
begin
  if true then
  begin
    { Do Interfaced Event to main form }
    Release;
  end;
end;

procedure TMainForm.Create(AOwner: TComponent);
begin 
  inherited;
  FormStyle := fsMDIForm;
  LoginForm := TLoginForm.Create(Application); {Create login form}
end;

procedure TMainForm.doLogout;
begin
  { Do Interfaced Event to Child Form except TLoginForm to close}

  if LoginForm <> nil then    {<== this still alocated at memory}
    LoginForm := TLoginForm.Create(Application)
  else
    LoginForm.Show; {<== Error raised here.}
end;
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Dicky Tamara
  • 211
  • 2
  • 14

2 Answers2

2

Release() is just a delayed destruction. It posts a CM_RELEASE message to the Form, and then the Form calls Free on itself when it processes that message.

Freeing a Form object (or any other object, for that matter) does not automatically set any pointers to that object to nil. You have to do that manually in your own code. In this case, you can set the global LoginForm pointer to nil in TLoginForm's destructor or OnDestroy event.

You might also consider using the TLoginForm.OnClose event instead of calling Release() directly. Have doLogin() call Close(), and when the Form is actually closed, set the event's Action parameter to caFree so the Form frees itself (via Release()). You still have to set the global LoginForm pointer to nil manually, though.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
1

Nowhere in your code do you set the variable LoginForm to nil. So it retains its value even after the object it refers to has been destroyed. If you wish this variable to be set to nil you must explicitly do that.

You should find this answer to a related question helpful: https://stackoverflow.com/a/8550628/

In essence, the issue behind your question can perhaps better be understood with this simple example:

obj := TObject.Create;
obj.Free;
Assert(Assigned(obj));

Destroying an object does not clear the variables that refer to it.

Yes, in your code you use Release rather than Free but the fundamental concept is exactly the same.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Mr. David, you right, i check the reason when i put checking at doLogout for resonable reason. so my method for checking was wrong when compare it to nil. https://stackoverflow.com/a/8550628/ was helpful for me. – Dicky Tamara Nov 21 '17 at 18:12