TOPページへ戻る  PCページへ戻る  一覧へ戻る TListのカスタマイズの目次へ戻る

Add、Clearメソッド、及びデストラクタの実装

Itemsプロパティにアイテムを追加する際、毎回PDouble型の変数を 使って代入しなくて済むよう、Addメソッドを実装します。また、すでに入っている値を クリアすることを考慮して、Clearメソッドを実装します。さらに、TMyList型の変数を 破棄する際、メモリリークになるItemsプロパティの破棄を忘れないよう、デストラクタ でItemsプロパティのメモリを解放します。

この改良を加えたコードは下のようになります。


type
  TMyList = class(TList)
  private
    function Get(Index:Integer):Double;
    procedure Put(Index:Integer; const Data:Double);
  public
    destructor Destroy;override;
    procedure Add(Data:Double);
    procedure Clear;override;
    property Items[Index:Integer]: Double read Get write Put; default;
  end;

destructor TMyList.Destroy;
begin
Clear;					// Clearメソッドを呼び出し、Itemsプロパティのメモリを解放
inherited Destroy;			// TListのDestroyを実行
end;

function TMyList.Get(Index:Integer):Double;
begin
Result := PDouble(inherited Get(Index))^;	// PDoubleでポインタをキャストし、^演算子で中身を参照
end;

procedure TMyList.Put(Index:Integer; const Data:Double);
begin
inherited Put(Index,@Data);			// @演算子でDataのアドレスを渡す
end;

procedure TMyList.Add(Data:Double);
var pd : PDouble;			// メモリ確保用のDoubleのポインタ型の変数
begin
New(pd);				// メモリ確保
try
pd^ := Data;				// ^演算子でポインタ変数pdにDouble型のDataを代入
inherited Add(pd);			// Itemsプロパティに値を追加
except
    Dispose(pd);			// 失敗した場合、確保したメモリを解放する
  end;
end;

procedure TMyList.Clear;
var i : Integer;
begin
i := 0;
while i < Count do
    begin
    if Assigned(List[i]) then Dispose(List[i]);	// ItemsプロパティのポインタであるListプロパティを調べ、
    Inc(i);					// メモリが確保されていたら破棄しnilを代入
    end;
inherited Clear;				// TListのClearを実行しItems用のメモリを解放
end; 

コードの説明

Add、Clear、デストラクタが追加されいますが、基本はItemsプロパティのメモリ操作 をする以外は、TListクラスの各メソッドを呼び出しているだけです。
 Addメソッドでは、New手続きでDouble型のメモリを確保し、引数のDataをそのメモリに確保して Itemsプロパティに追加しています。クリアメソッドでは、全てのListプロパティを調べてメモリが 確保されていたら廃棄しています。ここではItemsプロパティをカスタマイズしてDouble型になっている ため、Itemsプロパティのポインタが格納されているListプロパティをAssigned関数で調べています。
 デストラクタであるDestory手続きでは、TMyListのクリアを呼び出してItemsプロパティのメモリを 解放し、TListのデストラクタを実行しています。

使い方

型キャスト無しでItemプロパティを読み出す」で 作ったアプリケーションを上のTMyListを使って書き直すと次のようになります。


unit Unit1;

interface

uses
  SysUtils, Classes, Forms, Controls, StdCtrls;

type
  TMyList = class(TList)
  private
    function Get(Index:Integer):Double;
    procedure Put(Index:Integer; const Data:Double);
  public
    destructor Destroy;override;
    procedure Add(Data:Double);
    procedure Clear;override;
    property Items[Index:Integer]: Double read Get write Put; default;
  end;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Edit1: TEdit;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private 宣言 }
    ml : TMyList;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

// TMyListクラス
destructor TMyList.Destroy;
begin
Clear;
inherited Destroy;
end;

function TMyList.Get(Index:Integer):Double;
begin
Result := PDouble(inherited Get(Index))^;
end;

procedure TMyList.Put(Index:Integer; const Data:Double);
begin
inherited Put(Index,@Data);
end;

procedure TMyList.Add(Data:Double);
var pd : PDouble;
begin
New(pd);
try
pd^ := Data;
inherited Add(pd);
except
    Dispose(pd);
  end;
end;

procedure TMyList.Clear;
var i : Integer;
begin
i := 0;
while i < Count do
    begin
    if Assigned(List[i]) then Dispose(List[i]);
    Inc(i);
    end;
inherited Clear;
end;

// Form1クラス
procedure TForm1.Button1Click(Sender: TObject);
var st: TStringList;
    i : Integer;
begin
st := TStringList.Create;
try
ml.Clear;					// 新しい配列を作るため、古いものをクリア
st.CommaText := Edit1.Text;
i := 0;
while i < st.Count do
    begin
    try
    ml.Add(StrToFloat(st[i]));			// Double型の変数をそのまま追加
    except
        ;
      end;
    Inc(i);
    end;
finally
    FreeAndNil(st);
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var i: Integer;
    d: Double;
begin
i := 0;
d := 0;
while i < ml.Count do
    begin
    d := d + ml[i];
    Inc(i);
    end;
Label1.Caption := FloatToStr(d);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
ml := TMyList.Create;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FreeAndNil(ml);					// FreeAndNilでTMyList型の変数を破棄。
end;						// デストラクタが呼び出されてメモリが解放される

end. 

改善点・問題点

上のコードで、必要な機能はほとんど実装されたと思います。

次のページでは、Itemsプロパティの値を変更できるようにPut手続きを カスタマイズします。

次のページへ

TOPページへ戻る  PCページへ戻る  一覧へ戻る TListのカスタマイズの目次へ戻る