Solved

AV freeing TTable in destructor?

Posted on 1998-09-17
9
277 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
Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
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
 
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

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …
I've attached the XLSM Excel spreadsheet I used in the video and also text files containing the macros used below. https://filedb.experts-exchange.com/incoming/2017/03_w12/1151775/Permutations.txt https://filedb.experts-exchange.com/incoming/201…

821 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