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!
Related
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;
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.
I have simple thread safe container class. It has standard add/remove methods.
Normally enumerating items is implemented as:
MyList.lock;
try
// looping here
finally
MyList.unlock;
end;
But I want to take advantage of for-in support in a thread safe manner:
for item in MyList do
begin
// do something
end;
My enumerator implementation locks the container in it's contructor and unlocks it in the destructor. This works but lies on the assumption that Enumerator's instance is created at the beginning of for-in loop and is destroyed at the end. I found that explanation here: How is Enumerator created with for in construction destroyed?
But since locking/unlocking is a critical operation I wonder if this kind of usage is ok?
Here is my implementation:
TContainer<T> = class
private
FPadLock: TObject;
FItems: TList<T>;
protected
public
type
TContainerEnumerator = class(TList<T>.TEnumerator)
private
FContainer: TContainer<T>;
public
constructor Create(AContainer: TContainer<T>);
destructor Destroy; override;
end;
constructor Create;
destructor Destroy; override;
procedure add(AItem: T);
procedure remove(AItem: T);
function GetEnumerator: TContainerEnumerator;
end;
{ TContainer<T> }
procedure TContainer<T>.add(AItem: T);
begin
TMonitor.Enter(FPadLock);
try
FItems.Add(AItem);
finally
TMonitor.Exit(FPadLock);
end;
end;
constructor TContainer<T>.Create;
begin
inherited Create;
FPadLock := TObject.Create;
FItems := TList<T>.Create;
end;
destructor TContainer<T>.Destroy;
begin
FreeAndNil(FItems);
FreeAndNil(FPadLock);
inherited;
end;
procedure TContainer<T>.remove(AItem: T);
begin
TMonitor.Enter(FPadLock);
try
FItems.Remove(AItem);
finally
TMonitor.Exit(FPadLock);
end;
end;
function TContainer<T>.GetEnumerator: TContainerEnumerator;
begin
result := TContainerEnumerator.Create(self);
end;
{ TContainer<T>.TContainerEnumerator }
constructor TContainer<T>.TContainerEnumerator.Create(
AContainer: TContainer<T>);
begin
inherited Create(AContainer.FItems);
FContainer := AContainer;
TMonitor.Enter(FContainer.FPadLock); // <<< Lock parent container using Monitor
end;
destructor TContainer<T>.TContainerEnumerator.Destroy;
begin
TMonitor.Exit(FContainer.FPadLock); // <<< Unlock parent container
inherited;
end;
The enumerator is created at the start of the for loop, and destroyed when the loop ends. The lifetime of the enumerator is managed by a try/finally.
Don't just take my word for this though. It's easy enough to add some debugging code that will instrument your loop and let you see when the destructor is called.
This means that your proposed locking strategy is sound.
I would say though that allocating an enumerator on the heap, when you have thread contention, could cause performance problems.
If I have two overloaded constructors, one without and one with parameters:
constructor Create; overload;
constructor Create(Param: TObject); overload;
If I want the code in the first one to run, does it make sense to call it within the second one? And inherited to call the parent constructor first as well?
constructor TMyType.Create(Param: TObject);
begin
inherited Create;
Create;
FParam := Param;
end;
Thanks!
If I want the code in the first one to run, does it make sense to call it within the second one And inherited to call the parent constructor first as well?
No. Because your 1st constructor should call inherited one itself, so in the end the inherited constructor would get called twice, which it most probably does not expect.
Otherwise, if your parameterless TMyType.Create() does not call inherited one, then it is hardly a proper constructor and should be just removed.
So the correct approach would be like that:
constructor TMyType.Create(Param: TObject); overload;
begin
Create();
FParam := Param;
end;
constructor TMyType.Create(); overload;
begin
inherited Create(); // for both constructors
...some common code
end;
However in Delphi there is yet another possibility.
constructor Create; overload;
constructor Create(Param: TObject); overload;
procedure AfterConstruction; override;
constructor TMyType.Create(Param: TObject);
begin
inherited Create();
FParam := Param;
end;
constructor TMyType.Create();
begin
inherited ;
... maybe some extra code
end;
procedure TMyType.AfterConstruction();
begin
inherited;
...some common code
end;
Note the difference though, when would "common code" be executed and when would do "FParam := Param;"
In the 1st way, the flow would be like
Create (Param)
..Create()
....Inherited Create()
....Common Code
..FParam := Param;
AfterConstruction (empty)
In the second the sequence would be different
Create(Param) or Create()
..Inherited Create()
..FParam := Param;
AfterConstruction
..Common Code
As you can see the order of those chunks being executed got reversed.
However maybe you don't need multiple constructors at all?
constructor TMyType.Create(const Param: TObject = nil);
begin
inherited;
... Some code
FParam := Param;
end;
Yes your code makes perfect sense and the constructor's calls do exactly what one should expect.
Delphi object model supports both constructors that call inherited constructors and constructors that do not call inherited ones.
If you are not sure try this:
program Project5;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
TMyBase = class
constructor Create;
end;
TMyType = class(TMyBase)
constructor Create; overload;
constructor Create(Param: TObject); overload;
end;
constructor TMyBase.Create;
begin
Writeln('TMyBase.Create');
end;
constructor TMyType.Create;
begin
Writeln('TMyType.Create');
end;
constructor TMyType.Create(Param: TObject);
begin
inherited Create;
Create;
Writeln('TMyType.Create(Param)');
end;
begin
TMyType.Create(TObject.Create);
Readln;
end.
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.