Good day,
I have class
TMn2Adapter = class(TPersistent)
private
FGrid: TStringGridPointer;
FList: TList<string>;
// ...
public
constructor Create(AGrid: TStringGridPointer);
destructor Destroy();
end;
constructor TMn2Adapter.Create(AGrid: TStringGridPointer);
begin
FGrid := AGrid;
FList := TList<string>.Create();
end;
destructor TMn2Adapter.Destroy;
begin
Dispose(FGrid);
FList.Free;
FList := nil;
inherited;
end;
and another one
TMn2Worker = class(TPersistent)
private
FMn2Adapter: TMn2Adapter;
public
constructor Create(AGrid: TStringGridPointer);
destructor Destroy();
end;
constructor TMn2Worker.Create(AGrid: TStringGridPointer);
begin
FMn2Adapter := TMn2Adapter.Create(AGrid);
end;
destructor TMn2Worker.Destroy;
begin
SysUtils.FreeAndNil(FMn2Adapter);
inherited;
end;
procedure TMn2Adapter.Parse;
begin
FList.Clear();
for I := 1 to FLenght do FList.Add((FGrid)^.Cells[2, I]);
end;
Creating TMn2Worker in a form mn2: TMn2Worker, doing some action and onFormClose I free this one mn2.Free. And I get report from Eurekalog about memory leak (see attached image). It seems to me that something strange happen in a parsing TStringGrid`s cell to the TList.
Your destructor is never called because you did not include the override directive. Declare destructors like this:
destructor Destroy; override;
Some of the rest of your code looks dubious, although we can't see enough to be say anything for sure. Unfortunately you removed most of the relevant code. In one of the variants you call FreeAndNil on a reference that you already set to nil. That clearly is somewhat pointless. And in the other you Dispose a pointer that you didn't allocate which smells odd. Finally, it's not obvious why you would have a pointer to a reference type. That usually indicates a misunderstanding of reference type variable assignment.
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;
Why does this program report memory leaks?
{$APPTYPE CONSOLE}
uses
System.Generics.Collections;
type
TDerivedGenericObjectList = class(TObjectList<TObject>)
public
constructor Create;
end;
constructor TDerivedGenericObjectList.Create;
begin
inherited;
end;
var
List: TDerivedGenericObjectList;
begin
ReportMemoryLeaksOnShutdown := True;
List := TDerivedGenericObjectList.Create;
List.Add(TObject.Create);
List.Free;
end.
You are calling the parameterless constructor of TObjectList<T>. That is in fact the constructor of TList<T>, the class from which TObjectList<T> is derived.
All the constructors declared in TObjectList<T> accept a parameter named AOwnsObjects which is used to initialise the OwnsObjects property. Because you are bypassing that constructor, OwnsObjects is defaulting to False, and the members of the list are not being destroyed.
You should make sure that you call constructor of TObjectList<T> that initialise OwnsObjects. For instance:
{$APPTYPE CONSOLE}
uses
System.Generics.Collections;
type
TDerivedGenericObjectList = class(TObjectList<TObject>)
public
constructor Create;
end;
constructor TDerivedGenericObjectList.Create;
begin
inherited Create(True);
end;
var
List: TDerivedGenericObjectList;
begin
ReportMemoryLeaksOnShutdown := True;
List := TDerivedGenericObjectList.Create;
List.Add(TObject.Create);
List.Free;
end.
Perhaps a better variant would be to make your constructor also offer the AOwnsObjects parameter:
type
TDerivedGenericObjectList = class(TObjectList<TObject>)
public
constructor Create(AOwnsObjects: Boolean = True);
end;
constructor TDerivedGenericObjectList.Create(AOwnsObjects: Boolean);
begin
inherited Create(AOwnsObjects);
end;
Or:
type
TDerivedGenericObjectList = class(TObjectList<TObject>)
public
constructor Create(AOwnsObjects: Boolean = True);
end;
constructor TDerivedGenericObjectList.Create(AOwnsObjects: Boolean);
begin
inherited;
end;
So, you might wonder why the original version picked out a TList<T> constructor rather than one in TObjectList<T>. Well, let's look at that in more detail. Here's your code again:
type
TDerivedGenericObjectList = class(TObjectList<TObject>)
public
constructor Create;
end;
constructor TDerivedGenericObjectList.Create;
begin
inherited;
end;
When inherited is used in this way, the compiler looks for a constructor with the exact same signature as this one. It cannot find one in TObjectList<T> because they all have parameter. It can find one in TList<T>, and so that's the one that it uses.
As you mention in comments the following variant does not leak:
constructor TDerivedGenericObjectList.Create;
begin
inherited Create;
end;
This syntax, by contrast to the bare inherited, will find methods that match when default parameters are substituted. And so the single parameter constructor of TObjectList<T> is called.
The documentation has this information:
The reserved word inherited plays a special role in implementing polymorphic behavior. It can occur in method definitions, with or without an identifier after it.
If inherited is followed by the name of a member, it represents a normal method call or reference to a property or field, except that the search for the referenced member begins with the immediate ancestor of the enclosing method's class. For example, when:
inherited Create(...);
occurs in the definition of a method, it calls the inherited Create.
When inherited has no identifier after it, it refers to the inherited method with the same name as the enclosing method or, if the enclosing method is a message handler, to the inherited message handler for the same message. In this case, inherited takes no explicit parameters, but passes to the inherited method the same parameters with which the enclosing method was called. For example:
inherited;
occurs frequently in the implementation of constructors. It calls the inherited constructor with the same parameters that were passed to the descendant.
You can use generics. It's work fine without type casting and memory leak ( TObjectList<T> or TObjectDictionary<T> lists destroy inner objects automatic on free command).
Some tips:
TObjectList<TPerson> -- destroy persons list automatic on free like membersList.Free;
TList<TPerson> -- do not destroy persons list. You must create destructor and free manually every person in list;
Here is example of your code (using new constructor, no memory leak and with backward compatibility with old code -- see GetPerson):
type
TPerson = class
public
Name: string;
Age: Integer;
function Copy: TPerson;
end;
TMembers = class(TObjectList<TPerson>)
private
function GetPerson(i: Integer): TPerson;
public
property Person[i: Integer]: TPerson read GetPerson;
constructor Create(SourceList: TMembers); overload;
end;
{ TPerson }
function TPerson.Copy: TPerson;
var
person: TPerson;
begin
person := TPerson.Create;
person.Name := Self.Name;
person.Age := Self.Age;
Result := person;
end;
{ TMembers }
constructor TMembers.Create(SourceList: TMembers);
var
person: TPerson;
begin
inherited Create;
for person in SourceList do
begin
Self.Add(person.Copy);
end;
end;
function TMembers.GetPerson(i: Integer): TPerson;
begin
Result := Self[i];
end;
procedure TForm21.Button1Click(Sender: TObject);
var
person: TPerson;
memsList1: TMembers;
memsList2: TMembers;
begin
// test code
memsList1 := TMembers.Create;
person := TPerson.Create;
person.Name := 'name 1';
person.Age := 25;
memsList1.Add(person);
person := TPerson.Create;
person.Name := 'name 2';
person.Age := 27;
memsList1.Add(person);
memsList2 := TMembers.Create(memsList1);
ShowMessageFmt('mems 1 count = %d; mems 2 count = %d', [memsList1.Count, memsList2.Count]);
FreeAndNil(memsList1);
FreeAndNil(memsList2);
end;
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.
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.