4

次のクラスを実装しました。

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ですか? 私が知っていることから、反復は良い考えではありません。

4

1 に答える 1

11

TDictionaryに含まれるオブジェクトが自動的に解放されないため、コードによってメモリ リークが発生します。

オブジェクトをディクショナリに格納する必要がある場合は、TObjectDictionaryを採用する方が優れた方法です。

ディクショナリに含まれるオブジェクトを自動的に解放doOwnsValuesする場合は、コレクションのインスタンスを作成するときにフラグを使用します。

  • 変数が本当にグローバルな場合(つまり、ユニットvarのセクションで宣言されている場合)、ユニット自体のandセクションinterfaceで作成および破棄する必要があります。initializationfinalization

    . . .
    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クラスは 2 つの文字列とプロシージャへのポインターのみを所有するため、デストラクタを指定する必要はありません。したがって、から継承されたデフォルトのデストラクタでTObject十分です。

于 2015-08-26T08:35:30.687 に答える