Delphi dictionary release

I implemented the following classes:

type
TUtilProcedure = procedure(var AJsonValue: TJSONObject);< br />
TCallback = class
private
FName: string;
FProcedure: TUtilProcedure;
FAnnotation: string;
public
constructor Create (AName: string; AProcedure: TUtilProcedure; AAnnotation: string); overload;
constructor Create(ACallback: TCallback); overload;
property Name: string read FName;
property Proc: TUtilProcedure read FProcedure;
property Annotation: string read FAnnotation;
end;

Then I have a global variable:

procedures: TDictionary ;

In the OnFormActivate process, I initialize the process variables:

procedures := TDictionary.Create(); 
procedures.Add('something', TCallback.Create('sth', @proc,'annotation'));
// ....

Then in OnFormClose I release it:

procedures.Clear;
procedures.Free;

Does my code leak memory? If so, what is the correct way to interpret the dictionary?
As far as I know, iterating is not a good idea.

The code leaks memory because the TDictionary The contained objects will not be automatically released.

If you need to store objects in a dictionary, use TObjectDictionary to indicate a better way.

If you want to automatically release the dictionary For included objects, please use the doOwnsValues ​​flag when creating a collection instance.

>When the variable is actually a global variable (that is, declared as var in the interface part of the unit), it should be in the initialization and Create and destroy variables in the completion section.

...
var
procedures: TObjectDictionary;
...
initialization
procedures:= TObjectDictionary.Create([doOwnsValues]);
finalization
procedures.Free;

>When your When the variable belongs to the form class itself, you should create a dictionary in the OnCreate event of the form.

...
public
procedures: TObjectDictionary;
.. .
procedure TForm1.FormCreate(Sender: TObject);
begin
procedures:= TObjectDictionary.Create([doOwnsValues]);
end;

Release the dictionary in the OnDestroy event of the form:

procedure TForm1.FormDestroy(Sender: TObject);
begin
procedures.Free;
end;

>this In addition, if you want to access variables belonging to the class without an instance of the class itself (this is called a static variable in many programming languages), you can declare the dictionary as a class var and optionally access it through the class attribute; in this In this case, it is best to create and destroy the collection in the class constructor and class destructor.

...
TMyClass = class
private< br /> class constructor Create;
class destructor Destoy;
public
class var procedures: TObjectDictionary;
end;
.. .
class constructor TMyClass.Create;
begin
procedures := TObjectDictionary.Create([doOwnsValues]);
end;

class destructor TMyClass.Destoy;
begin
procedures.Free;
end;

TCallback = class
private
FName : string;
FProcedure: TUtilProcedure;
FAnnotation: string;
public
constructor Create(AName: string; AProcedure: TUtilProcedure; AAnnotation: string); overload;
constructor Create(ACallback: TCallback); overload;
property Name: string read FName;
property Proc: TUtilProcedure read FProcedure;
pr operty Annotation: string read FAnnotation;
end;

As a side note, the TCallback class does not need to specify a destructor, because it only has two strings and a pointer to the procedure. So from The default destructor inherited by TObject is sufficient.

I implemented the following class:

type 
TUtilProcedure = procedure(var AJsonValue: TJSONObject);

TCallback = class
private
FName: string;
FProcedure: TUtilProcedure;
FAnnotation: string;
public
constructor Create(AName: string; AProcedure: TUtilProcedure; AAnnotation: string); overload;
constructor Create(ACallback: TCallback); overload;
property Name: string read FName;
property Proc: TUtilProcedure read FProcedure;
property Annotation: string read FAnnotation;
end;

Then I have a global variable:

procedures: TDictionary;

In the OnFormActivate process, I initialize the process variables:

procedures := TDictionary.Create();
procedures.Add('something', TCallback.Create('sth', @proc,'annotation') );
// ....

Then I release it in OnFormClose:

procedures.Clear;
procedures .Free;

Is my code leaking memory? If so, what is the correct way to interpret the dictionary?
As far as I know, iteration is not a good idea.

The code leaks memory because the objects contained in TDictionary will not be automatically released.

< /p>

If you need to store objects in a dictionary, use TObjectDictionary to indicate a better method.

If you want to automatically release the objects contained in the dictionary, please use doOwnsValues ​​when creating a collection instance Flag.

>When the variable is actually a global variable (that is, declared as var in the interface part of the unit), the variable should be created and destroyed in the initialization and completion part of the unit itself.

.. .
var
procedures: TObjectDictionary;
.. .
initialization
procedures:= TObjectDictionary.Create([doOwnsValues]);
finalization
procedures.Free;

>When your variables belong to the form class itself, you should be in the form Create a dictionary in the OnCreate event.

.. .
public
procedures: TObjectDictionary;
.. .
procedure TForm1.FormCreate(Sender: TObject);
begin
procedures:= TObjectDictionary.Create([doOwnsValues]);
end;

Release the dictionary in the OnDestroy event of the form:

procedure TForm1.FormDestroy(Sender: TObject);
begin
procedures.Free;
end;

>In addition, if you want to access variables belonging to the class without an instance of the class itself (this is called a static variable in many programming languages), you can declare the dictionary as a class var and Optional via generic Access it sexually; in this case, it is better to create and destroy the collection in the class constructor and class destructor.

...
TMyClass = class
private
class constructor Create;
class destructor Destoy;
public
class var procedures: TObjectDictionary;
end;
.. .
class constructor TMyClass.Create;
begin
procedures := TObjectDictionary.Create([doOwnsValues]);
end;

class destructor TMyClass.Destoy;
begin
procedures.Free;
end;

TCallback = class
private
FName: string;
FProcedure: TUtilProcedure;
FAnnotation: string;
public
constructor Create(AName: string; AProcedure: TUtilProcedure; AAnnotation: string) ; overload;
constructor Create(ACallback: TCallback); overload;
property Name: string read FName;
property Proc: TUtilProcedure read FProcedure;
property Annotation: string read FAnnotation;
end;

As a side note , The TCallback class does not need to specify a destructor, because it only has two strings and a pointer to the procedure. Therefore, the default destructor inherited from TObject is sufficient.

< /p>

Leave a Comment

Your email address will not be published.