Delphi словарь освобождает

Я реализовал следующий класс:

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;

Тогда у меня есть глобальная переменная:

procedures: TDictionary<string, TCallback>;

В OnFormActivate процедура я инициализирую procedures переменная:

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

А потом в OnFormClose Я освобождаю это:

procedures.Clear;
procedures.Free;

Мой код пропускает память? Если да, то как правильно освободить dictionary? Из того, что я знаю, итерация не очень хорошая идея.

1 ответ

Решение

Код утечки памяти, потому что объекты, содержащиеся в TDictionary не освобождаются автоматически

Если вам нужно хранить объекты в словаре, принятие TObjectDictionary представляет собой лучший подход.

Если вы хотите, чтобы объекты, содержащиеся в словаре, были автоматически освобождены, используйте doOwnsValues флаг при создании экземпляра коллекции.

  • Когда переменная действительно глобальная (т.е. объявлена ​​в var в interface раздел блока), он должен быть создан и уничтожен в initialization а также finalization раздел самого блока.

    . . .
    var
      procedures: TObjectDictionary<string, TCallback>;
    . . .
    initialization
      procedures:= TObjectDictionary<string, TCallback>.Create([doOwnsValues]);
    finalization
      procedures.Free;
    
  • Когда ваша переменная принадлежит самому классу формы, вы должны создать словарь в форме OnCreate событие.

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

    Бесплатный словарь в форме OnDestroy событие:

    procedure TForm1.FormDestroy(Sender: TObject);
    begin
      procedures.Free;
    end;
    
  • Кроме того, если вы хотите, чтобы к переменной, принадлежащей классу, обращались без необходимости экземпляра самого класса (это называется статической переменной во многих языках программирования), вы можете объявить словарь как class var и при желании получить к нему доступ через class property; в таком случае лучше создать и уничтожить коллекцию в class constructor и в class destructor,

    . . .
    TMyClass = class
      private
        class constructor Create;
        class destructor Destoy;
      public
        class var procedures: TObjectDictionary<string, TCallback>;
    end;
    . . .
    class constructor TMyClass.Create;
    begin
      procedures := TObjectDictionary<string, TCallback>.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;

Как примечание стороны, TCallback В классе не нужно указывать деструктор, потому что он владеет только двумя строками и указателем на процедуру. И поэтому деструктор по умолчанию унаследован от TObject достаточно.

Другие вопросы по тегам