Solved

AV freeing TTable in destructor?

Posted on 1998-09-17
9
276 Views
Last Modified: 2010-04-06
Hi,

Can anyone fill me in why freeing the TTable, tbl, in unit2 (see below) causes an AV?

Thanks, Tom

unit pertest;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Menus;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

uses Unit2;

procedure TForm1.FormCreate(Sender: TObject);
begin
   myClass := TmyClass.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
   myClass.Free;
end;

end.

unit Unit2;

interface

uses SysUtils, DbTables, Classes, Forms, DB;

type
   TMyClass = class
      private
         tbl: TTable;
      public
         constructor Create;
         destructor Destroy; override;
    end;

var
   myClass: TMyClass;

implementation


constructor TMyClass.Create;
begin
   tbl := TTable.Create(Application);
end;

destructor TMyClass.Destroy;
begin
   tbl.Free;
end;

end.
0
Comment
Question by:tomcorcoran
  • 3
  • 2
  • 2
  • +2
9 Comments
 
LVL 10

Expert Comment

by:viktornet
ID: 1340089
Here is what you might want to do....
-------------


   unit pertest;

   interface

   uses
     Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
     Menus;

   type
     TForm1 = class(TForm)
       procedure FormCreate(Sender: TObject);
       procedure FormDestroy(Sender: TObject);
     private
       { Private declarations }
     public
       { Public declarations }
     end;

   var
     Form1: TForm1;

   implementation

   {$R *.DFM}

   uses Unit2;
var
  MyClass : TMyclass;
   procedure TForm1.FormCreate(Sender: TObject);
   begin
      myClass := TmyClass.Create(self);
   end;

   procedure TForm1.FormDestroy(Sender: TObject);
   begin
      myClass.Free;
   end;

   end.

   unit Unit2;

   interface

   uses SysUtils, DbTables, Classes, Forms, DB;

   type
      TMyClass = class(TTable)
         public
/some stuff
       end;
------------
0
 

Author Comment

by:tomcorcoran
ID: 1340090
Victor, thanks, what I showed was a srtipped won version of my problem, it does not make sense for me to descend from TTable. I'm just looking for an answer as to why it blows. Tom.
0
 
LVL 4

Expert Comment

by:itamar
ID: 1340091
Hi Tom,

I can't explain WHY this problem occurs, but I could fix it.

Of course, this is just an "thumbnail" of your hole problem, but perhaps I can help you somehow.

After changing the Destroy code to the following, AV didn't happen any more:

   destructor TMyClass.Destroy;
   begin
      tbl := nil;
      tbl.Free;
   end;

As I know, Free method should take care of it.

IHTH,
Itamar
0
 
LVL 1

Expert Comment

by:Edo082297
ID: 1340092
Hi Tom
  I could be way off, but when you originally create the table, you pass Application as the owner, so you are telling your application that it is responsible for freeing the table when it terminates. When you free your MyClass object, since it has a pointer to the table, it frees it (*but does not set the pointer to nil*). Then, when you close the application, your application tests the pointer it has (because you have added the table to it's Components array through the Owner parameter), sees that it is nil, and then tries to free SizeOf(TTable) bytes in no man's land, which it now has no right to touch. Itamars code circumvents this problem by setting the pointer to nil; as you know, Delphi tests the value of the pointer to see if it is nil before freeing the memory. Since it is nil, no freeing actually takes place. In fact, Viktornet's solution was (unwittingly? he didn't explain why you get your AV) the correct procedure, because the class is responsible for freeing the table (or memory, or whatever), and consequently your application will not try and free it since it has no knowledge of it.
  If this is incorrect, I would like to hear it.

HTH

Regards,
Edo


0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 5

Expert Comment

by:JimBob091197
ID: 1340093
Hi Tom

Edo's comment is correct, but here is a little more info.

You can let TTable be owned by Application (tbl := TTable.Create(Application) AND you can still free it yourself without setting the pointer to nil.
Itamar's comment (as Edo points out) makes calling "tbl.Free" after "tbl := nil" pointless because Free is not called for nil pointers.

So, how can you make Application own tbl AND free it yourself?  You must free tbl BEFORE Application starts freeing everything it owns.  This is the sequence of events when your app closes:

1)  Application gets ready to close.  (FormClose event)
2)  Application frees everything it owns
2a) Thus Form gets freed.  (FormDestroy event)
2b) Application also owns tbl, and since Application is in a loop freeing everything it owns it tries to free tbl.  BUT of course, you have already freed tbl in FormDestroy (step 2a) when you call MyClass.Free.

Hence the Acess Violation.

3 ways of getting around this:

1) As has been said, don't free the tbl yourself.  Application will free it for you since Application owns it.  BUT this is not ideal because it means that MyClass can be freed long before MyClass.tbl is freed.  In your case it doesn't matter because you are freeing MyClass when your form closes, but consider what would happen if you created 50 instances of MyClass, and then freed them all, BUT you only wanted to close the app much later.  The 50 "tbl" objects wouldn't be freed until the app closes, thus taking up extra memory.

2) Move MyClass.Free from FormDestroy to FormClose.  Thus the tbl will be freed BEFORE Application starts freeing its objects.  When tbl (or any component) is freed, it removes itself from its owner's (in this case Application) list of objects to free.  Thus when Application starts to free everything that it owns (step 2 above) it no longer owns tbl so all is fine.

3) In MyClass's constructor, don't give tbl an owner.  Just call "tbl := TTable.Create(nil);"
This is fine because you free tbl yourself, and therefore tbl doesn't need an owner to free it.  Owner is only needed for an object such as TTable so that you don't have to free TTable yourself.  It's quite safe to create a component such as TTable without an owner if you are 100% sure you will free it yourself, and in your example this is indeed the case.

Sorry if it's a bit long, but I hope it gives you a better understanding of the purpose of a component's Owner in Delphi.

Regards,
JB

0
 

Author Comment

by:tomcorcoran
ID: 1340094
Guys, thanks a lot. JimBob, that's great information, thanks a million for taking the time, I didn't know how all that worked. Solution 3 is the way for me, I was only using Application as owner as there was no form. Thanks again, Tom.
0
 

Author Comment

by:tomcorcoran
ID: 1340095
JimBob, do an answer so I can grade, thanks Tom.
0
 
LVL 4

Expert Comment

by:itamar
ID: 1340096
Hi Jim,

Great answer !

Where can I find documentation about the order of these main events that happens in the application.run, close, form creation and so on ?
0
 
LVL 5

Accepted Solution

by:
JimBob091197 earned 70 total points
ID: 1340097
Hi Tom

Here is the answer you requested.  Glad it helped you.

Itamar: I'm not sure where you can get the info you want.  The Delphi help is pretty useless.  There are probably some books that give the order of events, else I can help you too!  :-)

Cheers,
JB
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Save pdf file to other location 3 79
How to use Hashing sha1 in Delphi 2010 4 198
Path  to current project in Delphi. 2 71
Firemonkey DbLookupComboBox equivalent ? 2 32
A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

932 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now