Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2003-12

Order of destruction in TCustomListBox

26 messages · 7 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Vincent Snijders

Hi,

The destructor of TCustomListBox is:
destructor TCustomListBox.Destroy;
begin
  FreeAndNil(FCanvas);
  inherited Destroy;
  FreeAndNil(FItems);
end;

As I am implementing the TCheckListBox items collection for win32, I would like to access the listbox handle, while in the destructor of the items collection. Unfortunately the window (+ items + item data stored in it) are lost before the destructor for the items collection is called.

Therefore I want to ask, if it is possible to change to destructor to:
destructor TCustomListBox.Destroy;
begin
  FreeAndNil(FCanvas);
  FreeAndNil(FItems);
  inherited Destroy;
end;

If this is not possible, I will probably find another way to close the checklistbox without memory leaks, but changing this is easier for me.

Regards,
Vincent.

Reply by email

Mattias Gaertner
to Vincent Snijders
Show quoted text 26 lines
Hi, The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin FreeAndNil(FCanvas); inherited Destroy; FreeAndNil(FItems); end; As I am implementing the TCheckListBox items collection for win32, I would like to access the listbox handle, while in the destructor of the items collection. Unfortunately the window (+ items + item data stored in it) are lost before the destructor for the items collection is called. Therefore I want to ask, if it is possible to change to destructor to: destructor TCustomListBox.Destroy; begin FreeAndNil(FCanvas); FreeAndNil(FItems); inherited Destroy; end; If this is not possible, I will probably find another way to close the checklistbox without memory leaks, but changing this is easier for me.

What about:

destructor TCustomListBox.Destroy;
begin
  Destroying;
  DestroyWnd;
  FreeAndNil(FCanvas);
  inherited Destroy;
  FreeAndNil(FItems);
end;

The Destroying; can accelerate the destruction and DestroyWnd will clean up. Maybe such things should be added to more controls.

I think, we should keep fItems like the VCL until after the "inherited Destroy;".

Mattias

Reply by email

Micha Nelissen
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Mattias Gaertner wrote 12 lines
On Sun, 14 Dec 2003 15:09:48 +0100 Micha Nelissen wrote: ><output> >CB.SomeFunc call >Constructor ></output> > >Which is not logical, IMHO. It is just a matter of definition. Although it would be interesting how you imagine a more logical alternative.

The definition is: the object is only 'defined', if it's constructor has run completely. Something along those lines is used by C++. After each constructor run, and only then, are the overriden function pointers written to the VMT. Personally, I think this is more logical, although maybe it's a matter of personal taste.

Micha.

Reply by email

Mattias Gaertner
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Show quoted text 17 lines
Mattias Gaertner wrote: > On Fri, 12 Dec 2003 17:02:56 +0100 Vincent Snijders > wrote: > >>As I am implementing the TCheckListBox items collection for win32, I >>would like to access the listbox handle, while in the destructor of the >>items collection. Unfortunately the window (+ items + item data stored >>in it) are lost before the destructor for the items collection is >>called. >> > The Destroying; can accelerate the destruction and DestroyWnd will clean > up. Maybe such things should be added to more controls. > > I think, we should keep fItems like the VCL until after the "inherited > Destroy;". Do you know why the order is like it is in the VCL?

Only Borland knows for sure.
Probably because calling the inherited Destroy produces notifications, which can call code, that accesses the listbox items and would otherwise need some ifs.

Mattias

Reply by email

Mattias Gaertner
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Show quoted text 36 lines
Mattias Gaertner wrote: > On Sat, 13 Dec 2003 19:39:39 +0100 Micha Nelissen > wrote: > > >>Mattias Gaertner wrote: >> >> >>>On Sat, 13 Dec 2003 17:27:00 +0100 Micha Nelissen >>> wrote: >>> >>> >>> >>>>Mattias Gaertner wrote: >>>> >>>> >>>>>I think, we should keep fItems like the VCL until after the >"inherited>>>>Destroy;". >>>> >>>>Do you know why the order is like it is in the VCL? >>> >>> >>>Only Borland knows for sure. >>>Probably because calling the inherited Destroy produces notifications, >>>which can call code, that accesses the listbox items and would >otherwise>>need some ifs. >> >>Aah, the 'yucky'-ness of Object Pascal :-(. > > > What do you mean? I don't like the fact of pascal that it's possible that overriden functions get called although their constructor hasn't run or their destructor has run.

What function gets called after the destructor has run?

Mattias

Reply by email

Micha Nelissen
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Marc Weustink wrote 18 lines
At 22:22 13-12-2003, Micha Nelissen wrote: > Mattias Gaertner wrote: > >> >> What do you mean? > > > I don't like the fact of pascal that it's possible that overriden > functions get called although their constructor hasn't run or their > destructor has run. That has nothing to do with object pascal, but all with the one who designed the classes you're using. IMO calling virtuals in yuor constructor/destructor isn't a bad thing if you know what you're doing. If things has to be called in a certain order, that is nothing different than programming other routines.

I think you didn't understand what I was saying, please read my reply to Mattias for an example.

Regards,

Micha.

Reply by email

Mattias Gaertner
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Show quoted text 20 lines
Mattias Gaertner wrote: > On Sun, 14 Dec 2003 15:09:48 +0100 Micha Nelissen > wrote: >><output> >>CB.SomeFunc call >>Constructor >></output> >> >>Which is not logical, IMHO. > > > It is just a matter of definition. Although it would be interesting how > you imagine a more logical alternative. The definition is: the object is only 'defined', if it's constructor has run completely. Something along those lines is used by C++. After each constructor run, and only then, are the overriden function pointers written to the VMT. Personally, I think this is more logical, although maybe it's a matter of personal taste.

I got the feeling, Micha is talking about general OOP, while the answers are about implementation details in FPC/Delphi. I think, the real problem is that there are different definitions of OOP.

About your definition: "the object is only 'defined', if it's constructor has run completely."

No one will argue about this. Because it does not say a word about inherited constructors. I guess, you mean something like this:

"every class level of an object is only 'defined', if the constructor of this level has run completely."

This is the OO view, looking from the outside. You call the constructor to create and initialize an object (aka an instance of a class). Looking from the inside, no constructor is atomic. Creation and initialization are splittet and inherited constructors are parts of the initialization process. So, you can only say: "the object initialization is completed, when it's constructor has run completely." Inheritance means enhancing a class by adding and changing. The changing is important here. An inherited object is not just the old class plus some features. It can behave differently.
The constructor is no exception. The constructor is overriden and uses the inherited constructor, because this is the whole point of inheritance: to save code and to create "is a" relationships.

So, if you say, that an inherited constructor should create a complete defined ancestor class (and only this), then you have extended the OO model by some limits, and this way you can easily make Delphi's/FPC's object pascal illogical.

Of course you can also argue: Using another OO definition than FPC and saying FPC's OOP is not logical is illogical.

Mattias

Reply by email

Marc Weustink
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Micha Nelissen wrote 34 lines
Mattias Gaertner wrote: >On Sat, 13 Dec 2003 19:39:39 +0100 Micha Nelissen >wrote: > >>Mattias Gaertner wrote: >> >> >>>On Sat, 13 Dec 2003 17:27:00 +0100 Micha Nelissen >>> wrote: >>> >>> >>> >>>>Mattias Gaertner wrote: >>>> >>>> >>>>>I think, we should keep fItems like the VCL until after the "inherited >>>>>Destroy;". >>>> >>>>Do you know why the order is like it is in the VCL? >>> >>> >>>Only Borland knows for sure. >>>Probably because calling the inherited Destroy produces notifications, >>>which can call code, that accesses the listbox items and would otherwise >>>need some ifs. >> >>Aah, the 'yucky'-ness of Object Pascal :-(. > >What do you mean? I don't like the fact of pascal that it's possible that overriden functions get called although their constructor hasn't run or their destructor has run.

That has nothing to do with object pascal, but all with the one who designed the classes you're using. IMO calling virtuals in yuor constructor/destructor isn't a bad thing if you know what you're doing. If things has to be called in a certain order, that is nothing different than programming other routines.

Just my opiion on this,

Marc

Reply by email

Stoian Ivanov
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…

Hi all,

I'm monitoring this list from some time and this is the first time i notice a possible error condition:

Show quoted text 6 lines
> destructor TCustomListBox.Destroy; > begin > FreeAndNil(FCanvas); > inherited Destroy; > FreeAndNil(FItems); > end;

On heavy load the sytem can map-out the page containing the object's data once it is freed via inherited Destroy thus invalidating the refference to FItems (assuming it is a field mamber) the solution to the problem (if destruction odret is to be kept) should be:

destructor TCustomListBox.Destroy;
var
    stack_FItems:Txxxxxxx
begin
    stack_FItems:=FItems;
   FreeAndNil(FCanvas);
   inherited Destroy;
//  FItems:=nill;
  stack_FItems.Free;
end;

Reply by email

Micha Nelissen
to Marc Weustink: + From: Behalf Of + Michael Van Canneyt + Sent: maandag 15 december 2003 13:49 + + + > >
Marc Weustink wrote 17 lines
+ From: Behalf Of + Michael Van Canneyt + Sent: maandag 15 december 2003 13:49 + + On Mon, 15 Dec 2003, Micha Nelissen wrote: + + > >>The definition is: the object is only 'defined', if it's + > >>constructor has run completely. Something along those + > >>lines is used by C++. The way constructos/destructors and inherited parts in C++ are complete different then in object pascal. AFAIK the parent constructor/destructor is called implicitly OK, after some talks to the "real" C++ programmers overhere it is clear that one can do the same in C++ as we do in Delphi, so there is no real difference.

There is not?

Show quoted text 7 lines
+ > >>After each constructor run, and only then, are the overriden + > >>function pointers written to the VMT. Personally, I think + > >>this is more logical, although maybe it's a matter of personal taste. Ow ? AFAIK the vmt pointers are filled in before the constructor is called.

Oops, that needs to be: after the inherited constructor has run.

Micha.

Reply by email

Micha Nelissen
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Mattias Gaertner wrote 22 lines
On Sat, 13 Dec 2003 22:22:30 +0100 Micha Nelissen wrote: >Mattias Gaertner wrote: > > >>On Sat, 13 Dec 2003 19:39:39 +0100 Micha Nelissen >> wrote: >> >> >>>Aah, the 'yucky'-ness of Object Pascal :-(. >> >> >>What do you mean? > >I don't like the fact of pascal that it's possible that overriden >functions get called although their constructor hasn't run or their >destructor has run. What function gets called after the destructor has run?

We need some code :-).

<code>
program Virt;
{$mode objfpc}
{$h+}
type
CA = class
private
   procedure SomeFunc; virtual; abstract;
public
   constructor Create;
end;
CB = class(CA)
private
   procedure SomeFunc; override;
public
   constructor Create;
end;
constructor CA.Create;
begin
   SomeFunc;
end;
constructor CB.Create;
begin
   inherited;
   writeln('Constructor');
end;
procedure CB.SomeFunc;
begin
   writeln('CB.SomeFunc call');
end;
var
   VB: CB;
begin
   VB := CB.Create;
   VB.Free;
end.
</code>

<output>
CB.SomeFunc call
Constructor
</output>

Which is not logical, IMHO.

Regards,

Micha.

Reply by email

Michael Van Canneyt
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Micha Nelissen wrote 20 lines
Mattias Gaertner wrote: > On Sun, 14 Dec 2003 15:09:48 +0100 Micha Nelissen > wrote: >><output> >>CB.SomeFunc call >>Constructor >></output> >> >>Which is not logical, IMHO. > > > It is just a matter of definition. Although it would be interesting how you > imagine a more logical alternative. The definition is: the object is only 'defined', if it's constructor has run completely. Something along those lines is used by C++. After each constructor run, and only then, are the overriden function pointers written to the VMT. Personally, I think this is more logical, although maybe it's a matter of personal taste.

I can show you code where in the constructor a virtual method is called which does some additional initialization. The method needs to be virtual since the initialization is different depending on the descendent. That would not work in your scheme as it would be invalid code...

You would in such case require a separate call by the programmer, after the constructor, to do this initialization. That is not possible for instance in streaming. The streaming system has no way of knowing that some separate initialization is needed. This means that all initialization must be done in the constructor...

Michael.

Reply by email

Mattias Gaertner
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Show quoted text 20 lines
Mattias Gaertner wrote: > On Sat, 13 Dec 2003 17:27:00 +0100 Micha Nelissen > wrote: > > >>Mattias Gaertner wrote: >> >>>I think, we should keep fItems like the VCL until after the "inherited >>>Destroy;". >> >>Do you know why the order is like it is in the VCL? > > > Only Borland knows for sure. > Probably because calling the inherited Destroy produces notifications, > which can call code, that accesses the listbox items and would otherwise > need some ifs. Aah, the 'yucky'-ness of Object Pascal :-(.

What do you mean?

Mattias

Reply by email

Marc Weustink
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Micha Nelissen wrote 22 lines
Marc Weustink wrote: >At 22:22 13-12-2003, Micha Nelissen wrote: > >>Mattias Gaertner wrote: >> >>> >>>What do you mean? >> >> >>I don't like the fact of pascal that it's possible that overriden >>functions get called although their constructor hasn't run or their >>destructor has run. > >That has nothing to do with object pascal, but all with the one who >designed the classes you're using. IMO calling virtuals in yuor >constructor/destructor isn't a bad thing if you know what you're doing. >If things has to be called in a certain order, that is nothing different >than programming other routines. I think you didn't understand what I was saying, please read my reply to Mattias for an example.

I did understand what you were saying and I had the same example in mind when I wrote this.

From you example, I see no reason why the inherited constructor should be called first. (OK it was necesary when using objects, but not for classes) So in your derived class you can initialize all vars and then call inherited. I don't see why this violates OO. You are in the constructing phase of you object.
I've used many times abstract virtuals in my constructor, to force a constructing order and to be able to use "user defined" classes for member objects in derived classes.

Marc

Reply by email

Michael Van Canneyt
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Micha Nelissen wrote 32 lines
Michael Van Canneyt wrote: > > On Mon, 15 Dec 2003, Micha Nelissen wrote: > > >>Mattias Gaertner wrote: >> >> >>>On Sun, 14 Dec 2003 15:09:48 +0100 Micha Nelissen >>>wrote: >>> >>>><output> >>>>CB.SomeFunc call >>>>Constructor >>>></output> >>>> >>>>Which is not logical, IMHO. >>> >>> >>>It is just a matter of definition. Although it would be interesting how you >>>imagine a more logical alternative. >> >>The definition is: the object is only 'defined', if it's constructor has >>run completely. Something along those lines is used by C++. After each >>constructor run, and only then, are the overriden function pointers >>written to the VMT. Personally, I think this is more logical, although >>maybe it's a matter of personal taste. > > > I can show you code where in the constructor a virtual method is called Yes, show me the code :-).

Basically, it says the following:

Constructor TAppClientDataset.Create(AOwner : TComponent)
begin
  Inherited;
  // ... Various statements
  InitDataEvents;
end;

The data events that must be initialized depend on the descendent.

Now, we could put this call in 'Loaded', but then they are not initialized when we do for instance:

With TMySomeClientDataset.Create(Self) do
  Try
    // Do stuff.
  Finally
    Free;
  end;

This kind of code is quite common.

Alternatively, we could put the code from InitDataEvents in the constructor, and add additional initialization in the descendent constructors. But sometimes, the events must be re-initialized: That would mean duplicating the code from the constructor to a separate call.

For these reasons, the 'InitDataEvents' is called in the constructor and is virtual.

> which does some additional initialization. The method needs to be What kind of initialization should I be thinking about?

Anything. Data events, extra variables.

Show quoted text 6 lines
> virtual since the initialization is different depending on the > descendent. That would not work in your scheme as it would be invalid > code... That's the only way?

It's never the _only_ way, but definitely the most convenient in many cases.

Michael.

Reply by email

Marc Weustink
to Micha Nelissen: There is not? Oops, that needs to be: after the inherited constructor has run. Micha.

+ From: Micha Nelissen
+ Sent: maandag 15 december 2003 14:42
+
+ Marc Weustink wrote:
+
+ > + From:
+ Behalf Of
+ > + Michael Van Canneyt
+ > + Sent: maandag 15 december 2003 13:49
+ > +
+ > + On Mon, 15 Dec 2003, Micha Nelissen wrote:
+ > +
+ > + > >>The definition is: the object is only 'defined', if it's
+ > + > >>constructor has run completely. Something along those
+ > + > >>lines is used by C++.
+ >
+ > The way constructos/destructors and inherited parts in C++
+ > are complete different then in object pascal. AFAIK the parent
+ > constructor/destructor is called implicitly
+ >
+ > OK, after some talks to the "real" C++ programmers overhere
+ > it is clear that one can do the same in C++ as we do in Delphi,
+ > so there is no real difference.
+
+ There is not?

No, in the defenition part of the constructor, one can define the initialization of the locals and the call to the inherited. The order can be changed.

In pascal you get someting like:

constructor Create;
begin
  FItems := TList.Create;
  FCount := 0;
  inherited;
  //-------------------
  DoSomethingVirtual;
end;

Even if inherited would call someting virtual it is ok.

+ > + > >>After each constructor run, and only then, are the overriden
+ > + > >>function pointers written to the VMT. Personally, I think
+ > + > >>this is more logical, although maybe it's a matter of personal
+ > + > >>taste.
+ >
+ > Ow ? AFAIK the vmt pointers are filled in before the constructor is
+ > called.
+
+ Oops, that needs to be: after the inherited constructor has run.

Nope, before the the call to the constructor is made. The vmt is complete on the first entry of the constructor (even before the call to beforeconstruction)

If the vmt is filled in the constructor, one could never have virtual constructors.

Marc

Reply by email

Micha Nelissen
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Michael Van Canneyt wrote 29 lines
On Mon, 15 Dec 2003, Micha Nelissen wrote: >Mattias Gaertner wrote: > > >>On Sun, 14 Dec 2003 15:09:48 +0100 Micha Nelissen >>wrote: >> >>><output> >>>CB.SomeFunc call >>>Constructor >>></output> >>> >>>Which is not logical, IMHO. >> >> >>It is just a matter of definition. Although it would be interesting how you >>imagine a more logical alternative. > >The definition is: the object is only 'defined', if it's constructor has >run completely. Something along those lines is used by C++. After each >constructor run, and only then, are the overriden function pointers >written to the VMT. Personally, I think this is more logical, although >maybe it's a matter of personal taste. I can show you code where in the constructor a virtual method is called

Yes, show me the code :-).

which does some additional initialization. The method needs to be

What kind of initialization should I be thinking about?

virtual since the initialization is different depending on the descendent. That would not work in your scheme as it would be invalid code...

That's the only way?

Micha.

Reply by email

Vincent Snijders
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Show quoted text 47 lines
On Fri, 12 Dec 2003 17:02:56 +0100 Vincent Snijders wrote: > Hi, > > The destructor of TCustomListBox is: > destructor TCustomListBox.Destroy; > begin > FreeAndNil(FCanvas); > inherited Destroy; > FreeAndNil(FItems); > end; > > As I am implementing the TCheckListBox items collection for win32, I > would like to access the listbox handle, while in the destructor of > the items collection. Unfortunately the window (+ items + item data > stored in it) are lost before the destructor for the items > collection is called. > > Therefore I want to ask, if it is possible to change to destructor > to: destructor TCustomListBox.Destroy; > begin > FreeAndNil(FCanvas); > FreeAndNil(FItems); > inherited Destroy; > end; > > If this is not possible, I will probably find another way to close > the checklistbox without memory leaks, but changing this is easier > for me. What about: destructor TCustomListBox.Destroy; begin Destroying; DestroyWnd; FreeAndNil(FCanvas); inherited Destroy; FreeAndNil(FItems); end; The Destroying; can accelerate the destruction and DestroyWnd will clean up. Maybe such things should be added to more controls. I think, we should keep fItems like the VCL until after the "inherited Destroy;".

OK,

Some further investigation with the destructor as I proposed showed that listbox handle is already invalid before calling the inherited destroy. What happened I am not sure and I plan on doing things a little different, so I don't any changes to the the TCustomListBox destructor.

Regards,
Vincent.

Reply by email

Micha Nelissen
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Mattias Gaertner wrote 30 lines
On Sat, 13 Dec 2003 19:39:39 +0100 Micha Nelissen wrote: >Mattias Gaertner wrote: > > >>On Sat, 13 Dec 2003 17:27:00 +0100 Micha Nelissen >> wrote: >> >> >> >>>Mattias Gaertner wrote: >>> >>> >>>>I think, we should keep fItems like the VCL until after the "inherited >>>>Destroy;". >>> >>>Do you know why the order is like it is in the VCL? >> >> >>Only Borland knows for sure. >>Probably because calling the inherited Destroy produces notifications, >>which can call code, that accesses the listbox items and would otherwise >>need some ifs. > >Aah, the 'yucky'-ness of Object Pascal :-(. What do you mean?

I don't like the fact of pascal that it's possible that overriden functions get called although their constructor hasn't run or their destructor has run.

Micha.

Reply by email

Marc Weustink
to Michael Van Canneyt: Basically, it says the following: Constructor TAppClientDataset.Create(AOwner :…

+ From: Behalf Of
+ Michael Van Canneyt
+ Sent: maandag 15 december 2003 13:49
+
+ On Mon, 15 Dec 2003, Micha Nelissen wrote:
+
+ > Michael Van Canneyt wrote:
+ > >
+ > > On Mon, 15 Dec 2003, Micha Nelissen wrote:
+ > >
+ > >
+ > >>Mattias Gaertner wrote:
+ > >>
+ > >>
+ > >>>On Sun, 14 Dec 2003 15:09:48 +0100 Micha Nelissen
+ > >>> wrote:
+ > >>>
+ > >>>><output>
+ > >>>>CB.SomeFunc call
+ > >>>>Constructor
+ > >>>></output>
+ > >>>>
+ > >>>>Which is not logical, IMHO.
+ > >>>
+ > >>>
+ > >>>It is just a matter of definition. Although it would be
+ > >>>interesting how you imagine a more logical alternative.
+ > >>
+ > >>The definition is: the object is only 'defined', if it's
+ > >>constructor has run completely. Something along those
+ > >>lines is used by C++.

The way constructos/destructors and inherited parts in C++ are complete different then in object pascal. AFAIK the parent constructor/destructor is called implicitly

OK, after some talks to the "real" C++ programmers overhere it is clear that one can do the same in C++ as we do in Delphi, so there is no real difference.

+ > >>After each constructor run, and only then, are the overriden
+ > >>function pointers written to the VMT. Personally, I think
+ > >>this is more logical, although maybe it's a matter of personal taste.

Ow ? AFAIK the vmt pointers are filled in before the constructor is called.

+ > >
+ > >
+ > > I can show you code where in the constructor a virtual
+ > > method is called
+ >
+ > Yes, show me the code :-).
+
+ Basically, it says the following:
+
+ Constructor TAppClientDataset.Create(AOwner : TComponent) +
+ begin
+ Inherited;
+ // ... Various statements
+ InitDataEvents;
+ end;
+
+ The data events that must be initialized depend on the descendent.

You can also look at the various debugger classes. I've used it at several places, for instance to get the ClassType of the breakpoints in the Debugger.

+ Now, we could put this call in 'Loaded', but then they are not
+ initialized when we do for instance:
+
+ With TMySomeClientDataset.Create(Self) do
+ Try
+ // Do stuff.
+ Finally
+ Free;
+ end;
+
+ This kind of code is quite common.

Not only then, AFAIK loaded is only called if an object is loaded from stream. If you create for instance a TButton, if I recall it correctly, no call to Loaded is made.

+ Alternatively, we could put the code from InitDataEvents in the
+ constructor, and add additional initialization in the descendent
+ constructors. But sometimes, the events must be re-initialized:
+ That would mean duplicating the code from the constructor to
+ a separate call.
+
+ For these reasons, the 'InitDataEvents' is called in the
+ constructor and is virtual.
+
+ >
+ > > which does some additional initialization. The method needs to be
+ >
+ > What kind of initialization should I be thinking about? +
+ Anything. Data events, extra variables.

Or in my case retrieving classes etc.

+ > > virtual since the initialization is different depending on the
+ > > descendent. That would not work in your scheme as it would
+ > > be invalid code...
+ >
+ > That's the only way?
+
+ It's never the _only_ way, but definitely the most convenient in many
+ cases.

Yup.

Marc

Reply by email

Micha Nelissen
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Mattias Gaertner wrote 14 lines
On Fri, 12 Dec 2003 17:02:56 +0100 Vincent Snijders wrote: >As I am implementing the TCheckListBox items collection for win32, I >would like to access the listbox handle, while in the destructor of the >items collection. Unfortunately the window (+ items + item data stored >in it) are lost before the destructor for the items collection is >called. > The Destroying; can accelerate the destruction and DestroyWnd will clean up. Maybe such things should be added to more controls. I think, we should keep fItems like the VCL until after the "inherited Destroy;".

Do you know why the order is like it is in the VCL?

Micha.

Reply by email

Florian Klaempfl
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Stoian Ivanov wrote 18 lines
Hi all, I'm monitoring this list from some time and this is the first time i notice a possible error condition: >>destructor TCustomListBox.Destroy; >>begin >> FreeAndNil(FCanvas); >> inherited Destroy; >> FreeAndNil(FItems); >>end; On heavy load the sytem can map-out the page containing the object's data once it is freed via inherited Destroy thus invalidating the refference to FItems (assuming it is a field mamber) the solution to the problem (if destruction odret is to be kept) should be:

No, inherited destroy; doesn't release the memory of the current class. This is done after myobject.destroy; returns.

Reply by email

Micha Nelissen
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Mattias Gaertner wrote 40 lines
On Mon, 15 Dec 2003 09:01:47 +0100 Micha Nelissen wrote: >Mattias Gaertner wrote: > > >>On Sun, 14 Dec 2003 15:09:48 +0100 Micha Nelissen >> wrote: >> >>><output> >>>CB.SomeFunc call >>>Constructor >>></output> >>> >>>Which is not logical, IMHO. >> >> >>It is just a matter of definition. Although it would be interesting how >>you imagine a more logical alternative. > >The definition is: the object is only 'defined', if it's constructor has >run completely. Something along those lines is used by C++. After each >constructor run, and only then, are the overriden function pointers >written to the VMT. Personally, I think this is more logical, although >maybe it's a matter of personal taste. I got the feeling, Micha is talking about general OOP, while the answers are about implementation details in FPC/Delphi. I think, the real problem is that there are different definitions of OOP. About your definition: "the object is only 'defined', if it's constructor has run completely." No one will argue about this. Because it does not say a word about inherited constructors. I guess, you mean something like this: "every class level of an object is only 'defined', if the constructor of this level has run completely."

Indeed, this is more like what I meant.

[snip]

Of course you can also argue: Using another OO definition than FPC and saying FPC's OOP is not logical is illogical.

Well put, Mattias.

Micha.

Reply by email

Mattias Gaertner
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Show quoted text 78 lines
Mattias Gaertner wrote: > On Sat, 13 Dec 2003 22:22:30 +0100 Micha Nelissen > wrote: > > >>Mattias Gaertner wrote: >> >> >>>On Sat, 13 Dec 2003 19:39:39 +0100 Micha Nelissen >>> wrote: >>> >>> >>>>Aah, the 'yucky'-ness of Object Pascal :-(. >>> >>> >>>What do you mean? >> >>I don't like the fact of pascal that it's possible that overriden >>functions get called although their constructor hasn't run or their >>destructor has run. > > > What function gets called after the destructor has run? We need some code :-). <code> program Virt; {$mode objfpc} {$h+} type CA = class private procedure SomeFunc; virtual; abstract; public constructor Create; end; CB = class(CA) private procedure SomeFunc; override; public constructor Create; end; constructor CA.Create; begin SomeFunc; end; constructor CB.Create; begin inherited; writeln('Constructor'); end; procedure CB.SomeFunc; begin writeln('CB.SomeFunc call'); end; var VB: CB; begin VB := CB.Create; VB.Free; end. </code> <output> CB.SomeFunc call Constructor </output> Which is not logical, IMHO.

It is just a matter of definition. Although it would be interesting how you imagine a more logical alternative.

An object has always the same type, from the beginning till the end. That means from the very first line in any of its constructors till the last line in any destructor. For example: When a TControl comes down to the TObject constructor, it is still/already a TControl. For instance it does not create first a TObject, then a TPersistence, then a TComponent, then ... . This is OOP and is independent of object pascal.
Virtual Methods should always work the same. If called inside the constructor they do what they always do. For example: To forbid calling them inside the constructor of TComponent would mean: This is not yet a TControl, so you can't use the overriden methods - which is wrong. Only some variables are not yet initialized.

Mattias

Reply by email

Micha Nelissen
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Mattias Gaertner wrote 16 lines
On Sat, 13 Dec 2003 17:27:00 +0100 Micha Nelissen wrote: >Mattias Gaertner wrote: > >>I think, we should keep fItems like the VCL until after the "inherited >>Destroy;". > >Do you know why the order is like it is in the VCL? Only Borland knows for sure. Probably because calling the inherited Destroy produces notifications, which can call code, that accesses the listbox items and would otherwise need some ifs.

Aah, the 'yucky'-ness of Object Pascal :-(.

Micha.

Reply by email

Marc Weustink
to Vincent Snijders: The destructor of TCustomListBox is: destructor TCustomListBox.Destroy; begin…
Stoian Ivanov wrote 16 lines
Hi all, I'm monitoring this list from some time and this is the first time i notice a possible error condition: > > destructor TCustomListBox.Destroy; > > begin > > FreeAndNil(FCanvas); > > inherited Destroy; > > FreeAndNil(FItems); > > end; On heavy load the sytem can map-out the page containing the object's data once it is freed via inherited Destroy thus invalidating the refference to FItems (assuming it is a field mamber) the solution to the problem (if destruction odret is to be kept) should be:

I don't sure know for FPC (I asume it is), but this isn't the case for Delphi. The memory object is freed after destroy is called. Your statement is valid for good old TMyObj=object(TObject) but not for classes. So where inherited destroy is callled, the reference to FItems is valid intil you freed them yourself.

Marc.

Show quoted text 15 lines
destructor TCustomListBox.Destroy; var stack_FItems:Txxxxxxx begin stack_FItems:=FItems; FreeAndNil(FCanvas); inherited Destroy; // FItems:=nill; stack_FItems.Free; end; _________________________________________________________________ To unsubscribe: mail with "unsubscribe" as the Subject archives at http://www.lazarus.freepascal.org/mailarchives

Reply by email