Fundamental of "Free" in Delphi
Asked Answered
F

2

6

I have one fundamental doubt in Delphi. When I keep any component at design time, say for example TADOConnectuion and on button click even I write following code then I do not get any error:

begin
  ADOConnection.Free;  //No error
  ADOConnection.Free;  //No error
  ADOConnection.Free;  //No error
end;

But if I create the same object at run time as follwos I get "Access Violation..." error

begin
  ADOConnection := TADOConnection.create(self);
  ADOConnection.Free;  //No error
  ADOConnection.Free;  //Getting an "Access Violation..." error
end;

I get the same error even though I create the object as below:

ADOConnection := TADOConnection.create(nil);

Just would like to know the reason behind such behaviour, i.e. why there is no error when I keep the component at design time ?

Freehanded answered 30/8, 2012 at 8:53 Comment(2)
Related: why doesn't FreeAndNil really nil my object?Accouterment
Vishal, it's not useful (in fact it's discouraged) to add polite formulas to your questions and answers here on SO.Chicle
C
4

If you free a component, its corresponding field in the owner is cleared. If you add a design-time ADOConnection, then

ADOConnection.Free; // Frees ADOConnection and sets ADOConnection to nil
ADOConnection.Free; // Does nothing since ADOConnection is nil

You can see this by capturing it in a variable:

var c: TADOConnection;
c := ADOConnection;
c.Free; // Frees ADOConnection and sets ADOConnection to nil
c.Free; // Error: c is not set to nil

That won't work, even when ADOConnection is created at design time.

Here's an example with a TButton component that demonstrates how the behaviour you see for design-time components isn't specific to design-time components:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  published
    Button: TButton;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Assert(not Assigned(Button));
  TButton.Create(Self).Name := 'Button'; // Button field gets set
  Assert(Assigned(Button));
  Button.Free;                           // Button field gets cleared
  Assert(not Assigned(Button));
  Button.Free;                           // Okay, Free may be called on nil values
end;

end.
Chat answered 30/8, 2012 at 9:3 Comment(6)
Last doubt, why such behavior for design time and run time ?Freehanded
@VishalTiwari The difference isn't really between design time and run time, it's between owned and unowned. I'll include an example in a bit.Chat
The relevant code setting the ADOConnection to nil is in TComponent.SetReference and it is not directly related to Free, but more to RemoveComponent (which is called inside Destroy). This mechanism works when the owner has a field that is named like the child component.Chihuahua
@UweRaabe Indeed, the field is cleared when the component is renamed or removed, which can happen for other reasons than it being freed.Chat
But isn't it true, when you keep any component at design time, the "self" is the parent to that component, so when I cerate a component at runtime, by passing the "self" as a parameter to "Create" method, then it should behave like design time component, issue should come only when we are passing "NIL" as a parameter to "Create" method ?Freehanded
@VishalTiwari It requires that the component's owner (not the parent) is set, that the component has a name, that the component's owner has a published field with that same name, and that you access the component using that published field. That is the only field that will automatically be cleared when the component is removed.Chat
H
3

ADOConnection is initially nil so if you free it, the free function will not do anything because the pointer handed to it is nil. The pointer remains nil in the subsequent calls, so free keeps doing nothing. When you initialise ADOConnection with create, the pointer held in ADOConnection is no longer nil, so the first call to free will actively free the pointer, but subsequent calls will see that the memory has already been freed and raise an exception. The pointer is not changed by the call to free. For that, you'd need freeandnil instead.

Hendrik answered 30/8, 2012 at 8:58 Comment(3)
But some times FreeAndNil function also gives "Access Violation..." error without any reason, that's why I was working with .FreeFreehanded
@VishalTiwari: Have you actually looked at the code in FreeAndNil? That Access Violation most certainly is coming from somewhere, but I don't see how it could be caused by FreeAndNil and not by Free...Hued
@VishalTiwari: that kind of non-nil invalid reference is called stale pointer. Unless the destructor is so badly written that it throws an unhandled AV exception, the only way I remember to make FreeAndNil throws an AV is to pass to it an stale pointer....Doggone

© 2022 - 2024 — McMap. All rights reserved.