Solved

AV freeing TTable in destructor?

Posted on 1998-09-17
9
275 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
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 
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

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…

707 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