Solved

Strange problem with .Free

Posted on 2004-11-02
212 Views
Last Modified: 2010-04-05
I create into my VCL a listView.

constructor TMyVCL.Create( AOwner: TComponent);
.........
FList:=TListView.Create(AOwner);
FList.Parent:=Self;
FList.Visible:=False;
.....
end;

procedure TMyVCL.ShowMe;
begin
  FList.Parent:=GetParentForm(Self); //I wish to show it outside my vcl ( as a drop list of a TComboBox ).
  FList.Visible:=True;
end;

destructor .....
...
 FList.Free; // here get an error;
..
end;

If I create my VCL and not call ShowMe I can close my app very well ( destroy my vcl ). But if I can ShowMe before exit then I get an error message. Look like when I change the parent I can't free my FList.

I try with:
  FList.Parent :=Self; // reset the parent to Self as I declared on constructor;
  FList.Free;

But not succefully :(  What to do ?
0
Question by:ginsonic
    18 Comments
     
    LVL 7

    Expert Comment

    by:LRHGuy
    Once you assigned an "owner" to the listview, that owner becomes responsible for "freeing" the object. So, when your form closes, the object is alread gone before your flist.free executes.

    Either, don't call flist.free, or do:

    FList:=TListView.Create(nil);   //no owner

    and then do the flist.free yourself.

    I tested it, and it works.
    0
     
    LVL 1

    Assisted Solution

    by:vacerose
    When you reassign the Parent to the parent of TMyVCL the same process that calls your destructor is calling the destructor of the FList directly.  Your component is no longer responsible for freeing FList.

    From Delphi help:

    "The Parent property declared in TControl is similar to the Owner property declared in TComponent, in that the Parent of a control frees the control just as the Owner of a component frees that Component."
    0
     
    LVL 9

    Author Comment

    by:ginsonic
    Tested with:
      FList:=TListView.Create(nil);
    .......
      FList.Free;//error

    Tested with:
      FList.Parent:=Self; // I return to initial Parent
      FList.Free; // still error !?!?

    Tested with:
      FList:=TListView.Create(nil);
    ........
      FList.Parent:=Self; // I return to initial Parent
      FList.Free; // still error !?!?
    0
     
    LVL 7

    Expert Comment

    by:LRHGuy
    FList is "dead" in the FormDestroy routine...so you won't be able to assign the parent property either. Also, there's no need to.
    0
     
    LVL 7

    Expert Comment

    by:LRHGuy
    Oops...if you'd done:

    FList:=tListView.Create(nil);

    then

    FList.Parent:=Self;
    FList.Free;

    should work. Here's my code..no errors...


    procedure TForm2.FormCreate(Sender: TObject);
    begin
      FList:=TListView.Create(nil);
      FList.Parent:=Self;
      FList.Visible:=False;
    end;

    procedure TForm2.FormDestroy(Sender: TObject);
    begin
      flist.parent:=self; //not needed, we're destroying object anyway
      fList.free;
    end;

    procedure TForm2.Button2Click(Sender: TObject);
    begin
      FList.Parent:=GetParentForm(Self); //I wish to show it outside my vcl ( as a drop list of a TComboBox ).
      FList.Visible:=True;
    end;
    0
     
    LVL 9

    Author Comment

    by:ginsonic
    I think that in your demo Self is the Form himself and GetParentForm(Self) return same object. Or in my case Self is myVCL and GetParentForm(Self) is my form. How you can see in your demo have 2 objects ( form and listview) and in mine have 3 (form,vcl and list). Maybe I don't have right !?
    0
     
    LVL 7

    Expert Comment

    by:LRHGuy
    I tried several things and haven't been able to get an error on the free. Maybe if you show a little more code we can find the cause.
    0
     
    LVL 7

    Expert Comment

    by:LRHGuy
    Well, if the parent returned by GetParentForm() has been destroyed before you call FList.Parent:=Self (or :=nil), then you may get an error on THAT call...since the parent form is gone. (At least that's what seems to happen here.) As a result, the .Free gives an error. I've been able to create that problem.

    You'd have to make sure that FList.Parent:=nil before destorying the new parent.
    0
     
    LVL 5

    Expert Comment

    by:paulb1989
    Maybe try this in the destructor of your component.

    if FList.Parent=Self then
      FList.Free;
    0
     
    LVL 5

    Assisted Solution

    by:paulb1989
    To LRHGuy:

       I don't see how the form that FList is parented by can have been freed before calling the destructor of TMyVCL, as it is also the parent of the TMyVCL component. The form won't be gone whilst its components are still being freed. However, if FList is parented by the form when the destructor of TMyVCL is called, then FList may have already been freed by the form before TMyVCL.

    To ginsonic:
       If my code above doesnt work, try this.

       if Assigned(FList) then
         FList.Free;

       I have tested neither of them, so I'm not sure.
    0
     
    LVL 7

    Expert Comment

    by:LRHGuy
    Remember that FList can point to memory even if it has been freed.

    if you do:

    FList:=tListView.Create(nil);
    FList.Free;

    Then

    if Assigned(FList) is TRUE even though the memory has been freed.
    0
     
    LVL 7

    Accepted Solution

    by:
    Here's my test code. It works without errors...


    type
      Myvcl=class(tcombobox)
        constructor Create(aOwner:tcomponent); override;
        destructor destroy; override;
        procedure ShowIt;
        procedure HideIt;
      private
        FList:tlistview;
      end;

    type
      TForm2 = class(TForm)
        Button1: TButton;
        Button2: TButton;
        procedure FormCreate(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        procedure Button1Click(Sender: TObject);
      private
        fMY:MyVcl;
      end;

    implementation

    {$R *.dfm}

    { Myvcl }

    constructor Myvcl.Create(aOwner: tcomponent);
    begin
      inherited;
      FList:=TListView.Create(Self);
      FList.Parent:=Self;
      FList.Visible:=False;
      FList.Top:=Height;
    end;

    destructor Myvcl.destroy;
    begin
      {FList is freed automatically}
      inherited;
    end;

    procedure Myvcl.HideIt;
    begin
      FList.Visible:=False;
    end;

    procedure Myvcl.ShowIt;
    begin
      FList.Parent:=GetParentForm(Self);
      FList.Visible:=True;
    end;

    {TForm2}

    procedure TForm2.FormCreate(Sender: TObject);
    begin
      fMY:=Myvcl.create(Self);
      fMY.parent:=self;
      fMY.top:=30;
    end;

    procedure TForm2.Button2Click(Sender: TObject);
    begin
      fMy.showit;
    end;

    procedure TForm2.Button1Click(Sender: TObject);
    begin
      fMY.HideIt;
    end;
    0
     
    LVL 9

    Author Comment

    by:ginsonic
    On this moment I use same idea. No FList.Free, but not sure if is freed automatically.
    0
     
    LVL 17

    Assisted Solution

    by:geobul
    Hi,

    Try with the following destructor:

    destructor TMyVCL.Destroy;
    var c: TComponent;
    begin
      if Assigned(FList) then begin
        FList.Parent := nil;
        c := FList.Owner;
        if Assigned(c) then c.RemoveComponent(FList);
        FList.Free;
      end;
      inherited;
    end;

    Regards, Geo
    0
     
    LVL 17

    Expert Comment

    by:geobul
    You ARE obliged to free FList in any case. Just imagine that your TMyVCL has been created without an owner (i.e. nil). Who will be responsible for freeing FList then?
    0
     
    LVL 7

    Expert Comment

    by:LRHGuy
    Regardless of MyVCL has an owner, FList is owned by MyVCL, so if MyVCL is freed, so will FList.

    Also, if the object assigned to FList is freed by it's owner (which is usually the case) then the object pointer to by FList is gone, by FList still points to it's memory, hence Assigned(FList) returns true (it is assigned) but FList points to already releases memory.

    In Summary,

    if you, in Create():
      FList:=tlistview.create(nil);
    then you must, in Destroy():
      FList.Free;

    if you, in Create():
      FList.tlistview.create(self);
    then you should not, in Destroy():
      FList.Free
    since the owner will handle it automatically.
    0
     
    LVL 9

    Author Comment

    by:ginsonic
    Thanks for support and HAPPY NEW YEAR!
    0
     
    LVL 17

    Expert Comment

    by:geobul
    Happy New Year to all of you ! Wish you all the best, good health, luck and love :-)
    0

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    Course: JavaScript Coding - Massive 12-Part Bundle

    Regardless of your programming skill level, you'll go from basics to advanced concepts in a vast array of JavaScript subjects including Sammy.js, Agility.js, Ember.js, Node.js, jQuery, AJAX, Extjs, AngularJS, Knockout.js, and JSON.

    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…
    Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
    Migrating to Microsoft Office 365 is becoming increasingly popular for organizations both large and small. If you have made the leap to Microsoft’s cloud platform, you know that you will need to create a corporate email signature for your Office 365…
    Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

    857 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

    20 Experts available now in Live!

    Get 1:1 Help Now