TObjectList and destructor custom class - delphi

i use custom class TFrame in TObjectList. TFrame contain ListBoxItem and record's.
Š•heir parent can only be TListBox.
TFrame = class
ListboxItem: TListBoxItem;
Name: string;
PosStart,
PosEnd : integer;
Max: TData;
Min: TData;
Sqrt: TData;
constructor Create (ListBox: TListBox);
destructor Destroy;
end;
destructor TFrame.Destroy;
begin
ListboxItem.destroy;
end;
how to write a destructor for correct deletion with ObjectList.Delete(i)?
Now if ill try to delete - i have visible items with exception message.
Ty much!

Your destructor needs to override the base class destructor
destructor Destroy; override;
Otherwise it won't be called by Free.
And you should also call the inherited destructor.
destructor TFrame.Destroy;
begin
ListboxItem.Free;
inherited;
end;
Also, use Free rather than calling a destructor directly so that your code is protected against nil references.
There may well be other bugs in the code we can't see.

Related

How can I initialize my custom IdIOHandler fields?

This is blowing my mind... I just want to make a new IdIOHandler, and, as usual, I need to do some initialization in the constructor... Normally, I override the constructor of the base class, but this TIdIOHandlerStack which I inherit from, is far from "normal" ! It has no constructor to override, and is not known (to me) how it is created.
TIdEnhancedIOHandler = class(TIdIOHandlerStack)
private
FSendBuffer: TIdBytes;
FSendBuff: TDataStream;
public
constructor Create; // <-- I tested all the variations here, but non of them work
destructor Destroy; override;
end;
implementation
constructor TIdEnhancedIOHandler.Create;
begin
inherited Create;
FSendBuff:= TDataStream.Create(#SendBuffer);
end;
destructor TIdEnhancedIOHandler.Destroy;
begin
FSendBuff.Free;
inherited;
end;
initialization
TIdEnhancedIOHandler.SetDefaultClass;
Where should I put my intitialization code so that it is executed when a new instance of TIdEnhancedIOHandler is created BY DEFAULT in all Indy Components which use IOHandlers ?
I found it... It was the InitComponent method that I must override.
TIdEnhancedIOHandler = class(TIdIOHandlerStack)
private
FSendBuffer: TIdBytes;
FSendBuff: TDataStream;
public
procedure InitComponent; override;
destructor Destroy; override;
end;
implementation
procedure TIdEnhancedIOHandler.InitComponent;
begin
inherited;
FSendBuff:= TDataStream.Create(#SendBuffer);
end;

How to respond to changes in fields of object properties in Delphi

In Delphi 7, descend a new component from TGraphicControl, and add a TFont property, implement the paint method to write some string using the TFont property. Install the component.
At design time when you change the TFont property using the property dialog, it will be reflected in your component instantaneously. But when you change individual properties of TFont like Color or Size, your component will not be repainted until you hover over it.
How do I correctly handle changes in fields of object properties?
Assign an event handler to the TFont.OnChange event. In the handler, Invalidate() your control to trigger a repaint. For example:
type
TMyControl = class(TGraphicControl)
private
FMyFont: TFont;
procedure MyFontChanged(Sender: TObject);
procedure SetMyFont(Value: TFont);
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property MyFont: TFont read FMyFont write SetMyFont;
end;
constructor TMyControl.Create(AOwner: TComponent);
begin
inherited;
FMyFont := TFont.Create;
FMyFont.OnChange := MyFontChanged;
end;
destructor TMyControl.Destroy;
begin
FMyFont.Free;
inherited;
end;
procedure TMyControl.MyFontChanged(Sender: TObject);
begin
Invalidate;
end;
procedure TMyControl.SetMyFont(Value: TFont);
begin
FMyFont.Assign(Value);
end;
procedure TMyControl.Paint;
begin
// use MyFont as needed...
end;

How to create a TStringList descendant with Owner that will auto free the TStringList?

I'm hoping to create something like a "TOwnedStringList" (class name is a fiction) that I could construct as:
sl := TOwnedStringList.Create(Self);
sl.Sorted := True;
sl.Duplicates := dupIgnore;
sl.Add(...);
// etc...
Where Self could be a Form (for example), so that the Owner will auto free the StringList.
I want to be able to avoid calling sl.Free myself.
Is This possible?
That's going to be a little messy. You'd need to do something like this.
type
TOwnerComponent = class(TComponent)
private
FOwnedObject: TObject;
public
constructor Create(Owner: TComponent; OwnedObject: TObject);
destructor Destroy; override;
end;
TOwnedStringList = class(TStringList)
private
FOwner: TOwnerComponent;
public
constructor Create(Owner: TComponent);
destructor Destroy; override;
end;
{ TOwnerComponent }
constructor TOwnerComponent.Create(Owner: TComponent; OwnedObject: TObject);
begin
inherited Create(Owner);
FOwnedObject := OwnedObject;
end;
destructor TOwnerComponent.Destroy;
begin
FOwnedObject.Free;
inherited;
end;
{ TOwnedStringList }
constructor TOwnedStringList.Create(Owner: TComponent);
begin
inherited Create;
if Assigned(Owner) then
FOwner := TOwnerComponent.Create(Owner, Self);
end;
destructor TOwnedStringList.Destroy;
begin
if Assigned(FOwner) and not (csDestroying in FOwner.ComponentState) then
begin
FOwner.FOwnedObject := nil;
FOwner.Free;
end;
inherited;
end;
Basically you create an instance of TOwnerComponent that is owned by the Owner that you pass to TOwnedStringList.Create. When that Owner dies, it destroys the TOwnerComponent which in turn destroys your string list.
The code is resilient to an explicit Free being called on the string list.

Why is Destroy not called?

Given the following Delphi code, Foo is Free'd on FormClose, but TFoo.Destroy is not being called - and therefore Bar is not Free'd, leading to a memory leak?
Have I missed something here or shouldn't Foo.Free call Foo.Destroy at some point?
type
TBar = class
SomeInteger : integer;
end;
TFoo = class
Bar : TBar;
constructor Create();
destructor Destroy();
end;
var
Foo : TFoo;
implementation
constructor TFoo.Create;
begin
Bar := TBar.Create;
Bar.SomeInteger := 2;
end;
destructor TFoo.Destroy;
begin
Bar.Free;
Bar := nil;
showmessage('Destroyed!');
end;
procedure TForm10.FormCreate(Sender: TObject);
begin
Foo := TFoo.Create;
showmessage('Foo created');
end;
procedure TForm10.FormDestroy(Sender: TObject);
begin
Foo.Free;
Foo := nil;
end;
You must mark the signature of destructor with override.
destructor Destroy(); override;
And you should have inherited at the end of the destructor. But since your class is not derived from anything other than TObject I suspect that doesn't matter.
Destroy is virtual, and therefore you must override it in your descendant class.
TFoo = class
Bar : TBar;
constructor Create();
destructor Destroy(); override; // must add override here
end;
Without the override, your destructor is never called, and the base class one is instead.

How to create an instance that can not be destroyed

Imagine I have a class: TCantBeDestroyed
Some one knows how to create a kind of instance that can't be destroyed in both cases, directly:
CantBeDestroyed.Free;
CantBeDestroyed.Destroy;
And can't be destroyed by cast:
TObject(CantBeDestroyed).Free;
TObject(CantBeDestroyed).Destroy;
Tks.
You can't stop anyone calling a destructor or Free, but you can make sure that doing so has no effect:
type
TCannotBeDestroyed = class
public
destructor Destroy; override;
procedure BeforeDestruction; override;
procedure FreeInstance; override;
end;
destructor TCannotBeDestroyed.Destroy;
begin
//don't call inherited
end;
procedure TCannotBeDestroyed.BeforeDestruction;
begin
//don't call inherited
end;
procedure TCannotBeDestroyed.FreeInstance;
begin
//don't call inherited
end;
I can't imagine why you would want to do this though!

Resources