Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

An object calling it's own destructor

Status
Not open for further replies.

Griffyn

Programmer
Jul 11, 2002
1,077
AU
Hi all,

I came across the need to do this and the Delphi help file warns against it if you're doing it within a component's event handler. I'm not sure of the specifics of why this is, and so I wanted to get some feedback on whether I can safely do this sort of thing in a general sense. Some code:
Code:
type
  TMyObject = class(TObject)
    procedure DoSomethingAndFree;
  end;

implementation

procedure TMyObject.DoSomethingAndFree;
begin
  { ... Do something here ... }
  Free;
end;

var
  a : TMyObject;
begin
  a := TMyObject.Create;
  a.DoSomethingAndFree;
end;

I can't see why I shouldn't be able to do this - but the help file has scared me a little. Obviously - I could leave out the call to Free in the MyObject method, and instead do this:
Code:
  a := TMyObject.Create;
  a.DoSomething;
  a.Free;

But, in this instance I will always be needing the object freed immediately after a call to DoSomething. Can I call Free within the MyObject method?
 
I came across the need to do this...
It might help if you explained the need.

I find it quite simple to use a global instantiantion function. This example uses a TForm, but any type of object can be created, processed and freed in the same way.
Code:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes,
  Graphics, Controls, Forms,Dialogs, StdCtrls,
  ExtCtrls, contnrs, math;

{Instantiation function}
function ShowThisDialog(AKeyValue:integer):boolean;

type
  TdlgSomething = class(TForm)
    pbOk: TButton;
    pbCancel: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    FKeyValue:integer;
    procedure SetupDialog;
  public
    { Public declarations }
  end;

var
  dlgDoSomething: TdlgDoSomething;

implementation

{$R *.dfm}

function ShowThisDialog(AKeyValue:integer):boolean;
begin
  dlgDoSomething := TdlgDoSomething.Create(nil);
  with dlgDoSomething do
    try
      FKeyValue := AKeyValue;
      SetupDialog;
      dlgAnalysisParameters.ShowModal;
      Result := (ModalResult = mrOk);
    finally
      dlgDoSomething .Free;
    end;
end;
:
:
:
If that doesn't give you any ideas for a solution, post back with some specifics.

 
Hi Zathras,

I appreciate your thoughts, but I think you've misunderstood my question entirely. To be honest I don't quite know how to explain it any better than I did in my first post. But - building on your example, my question centres on 'Would it be ok for the SetupDialog method to free it's own instance?'

I deliberately left out my reason for this in order to make a simple example. But you asked, so:

I have an object class that each instance represents a table record. It contains methods to find it's own record in the table and report on the field values (and change them) as necessary. It's ok to Free the object instance without deleting it's underlying record, but it also has a Delete method which Deletes the underlying record, and then, because it has no further use and any use of it's properties will result in a error, it tries to Free itself. So the method look like this:

Code:
procedure TDBWrapper.Delete;
begin
  Owner.Table.Delete;   // Owner contains a TADOTable
  Free;
end;

So my question again is: Is this ok? Because the help file states that event handlers should never destroy their own instance. And I don't understand why, and/or/if my example is also wrong.
 

It's a bit like trying to pick up a rug when you are standing on it. If you jump and time it just right it can work. But if Delphi needs to execute any more code from your object (such as returning from the method handler) the instruction to do that may have been overwritten before you get to it. Probably not, but why take the chance?

I asked you to explain why you feel you have a NEED to do that. You did not answer the question. I don't care WHAT you are doing. If it works, fine. Go for it. But the custom is to free an object from the same level as it was created. So far, I have never found any case where that was not possible. Hence my question.

 
Hi Zathras & Griffyn,
there is a case where a VCL object frees itself :
TForm does this an the FormClose event when you set the closeaction to caFree.
this is what happens in reality (pasted some code from the Forms unit) :

Code:
procedure TCustomForm.CMRelease;
begin
  Free;
end;

procedure TCustomForm.Close;
var
  CloseAction: TCloseAction;
begin
  if fsModal in FFormState then
    ModalResult := mrCancel
  else
    if CloseQuery then
    begin
      if FormStyle = fsMDIChild then
        if biMinimize in BorderIcons then
          CloseAction := caMinimize else
          CloseAction := caNone
      else
        CloseAction := caHide;
      DoClose(CloseAction);
      if CloseAction <> caNone then
        if Application.MainForm = Self then Application.Terminate
        else if CloseAction = caHide then Hide
        else if CloseAction = caMinimize then WindowState := wsMinimized
        else Release;
    end;
end;

procedure TCustomForm.Release;
begin
  PostMessage(Handle, CM_RELEASE, 0, 0);
end;

as you can see, there are cases where's it's ok

--------------------------------------
What You See Is What You Get
 
But notice the careful way this is done by posting a message to itself, thus allowing all other processing to complete normally. This is not what Griffyn was suggesting.

Calling Free from inside the object works because at present the memory is not cleared. The Operating System only takes notice that it can be re-used. But consider what might happen in the future when a more security-conscious O/S actually writes over the memory being freed (so some snoop program can't read passwords, account numbers, PINs, etc. from the freed but still readable memory). Under those conditions, when the Free method returns control to its caller (DoSomethingAndFree), the return to caller instruction reqyured for passing control back to the caller of the DoSomethingAndFree method will no longer be there and the program will crash (or worse).

So there IS NO NEED (which was the original premise) for this dangerous kind of programming. It only lays a trap for some future maintenance programmer who won't be expecting that kind of structure.

Merely implement a Destroy method for the object and delete your table (or whatever) there, where the future maintenance programmer will be expecting to find it.

 
or you can always use an objectlist that frees the object for you when you delete it from the list...

--------------------------------------
What You See Is What You Get
 

whosrdaddy: I don't think you really meant to say it that way. Deleting an entry from a TObjectList does not free the object.

Freeing the TObjectList itself will free the objects in the list, assuming the AOwnsObjects parameter was True (the default value) when the list was created.


 
duh it really does (read help!)

--------------------------------------
What You See Is What You Get
 
right from the horses mouth :

Code:
Class 
TObjectList 

Syntax 


[Delphi] public property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects;


Description 
OwnsObjects allows TObjectList to control the memory of its objects. If OwnsObjects is true (the default),
 
calling Delete or Remove frees the deleted object in addition to removing it from the list.
 
calling Clear frees all the objects in the list in addition to emptying the list.
 
calling the destructor frees all the objects in the list in addition to destroying the TObjectList itself.
 
assigning a new value to an index in Items frees the object that previously occupied that position in the list.
 
Even if OwnsObjects is true, the Extract method can be used to remove objects from the list without freeing them.

--------------------------------------
What You See Is What You Get
 
Ah. Sorry about that. That's what I get when I don't read the titles on pages. I selected the Delete property from the TObjectList main help window and didn't notice that it took me to the TList delete method. You are absolutely correct. I just never noticed that feature before.

Never too old to learn something new. Thanks.

 
np man [2thumbsup]

made that same mistake years ago, and in result I never used TObjectlist. but now I almost use it in every new project...

cheers
[pc2]

--------------------------------------
What You See Is What You Get
 
I haven't read all the answers to your question, but the first thing comes in my mind is to override the destoy procedure, and add a DoSomething procedure before the "Inherited Destroy" call...


KungTure-RX.jpg

//Nordlund
 
Thanks for all your feedback everyone. Nordlund, I don't always want to DoSomething every time I free the object - it's the other way around. But thank you too for your time.

I'm going to take the safe route and force the programmer to call DoSomething, and then Free. And if the object is accessed inbetween then it will raise an exception.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top