Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

AV freeing TTable in destructor?

Posted on 1998-09-17
9
Medium Priority
?
280 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
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 280 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 The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Do you want to know how to make a graph with Microsoft Access? First, create a query with the data for the chart. Then make a blank form and add a chart control. This video also shows how to change what data is displayed on the graph as well as form…
In this video, Percona Solutions Engineer Barrett Chambers discusses some of the basic syntax differences between MySQL and MongoDB. To learn more check out our webinar on MongoDB administration for MySQL DBA: https://www.percona.com/resources/we…
Suggested Courses

722 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