델파이 TDictionary TObjectDictionary
사용 완료후 아이템 메모리 해제
델파이 2009에 새로 추가된 TDictionary 클래스 입니다.
우선 클래스는 Generics.Collections 에 들어 있습니다.
소스를 보시면
TDictionary<TKey,TValue>
이런 형태로 정의가 되어 있습니다.
사용법은 hash table과
거의 흡사하다고 보시면 됩니다.
key값과 value가 변경될때 이벤트도 발생
시켜 주기 때문에 이벤트를 연결해서
사용할 수도 있습니다.
hash table과 검색 속도를 비교해 봤는데
데이터가 많아질수록 이 클래스가 빨랐습니다.
뭐 hash table도 데이터가 많아질때
좋은 속도를 낸다는 점에서는 비슷하기는 하지만
어쨌든 제가 테스트한 hash table과
Dictionary에서는 Dictionary가 빨랐습니다.
그럼 아주 심플한 사용 예를 보여 드리겠습니다.
예를 들어 클라이언트를 관리 한다고 하면
var
Dic : TDictionary<string, TMyClient>;
begin
Dic := TDictionary<string, TMyClient>.Create;
try
Dic.Add('cli001', Myclient);
// 어쩌구 저쩌구~~~ //
finally
Dic.Free;
end;
end;
이런식으로 사용하고 key값으로 검색을 하시면 됩니다.
아래 샘플을 보시면 Memory Leak이 발생 한다고 하는데
마지막 Free 전에 Values 와
KeyCollection을 Free 시켜주면 된답니다.
procedure TForm4.Button2Click(Sender: TObject);
var
Dic : TDictionary<Integer,TPerson>;
p : TPerson;
i : integer;
begin
//Create dictionary
Dic := TDictionary<Integer,TPerson>.Create;
Dic.Add(1, TPerson.Create('Delphi', 'Mr'));
Dic.Add(2, TPerson.Create('Generic', 'Bill'));
Dic.Add(3, TPerson.Create('nonymous', 'An'));
try
//Travel the strings
for p in Dic.Values do begin
ShowMessage(p.FullName);
end;
//Travel the keys
for i in Dic.Keys do begin
ShowMessage(IntToStr(i) + ': ' +
Dic.Items[i].FullName);
end;
//Find some key
if Dic.TryGetValue(3, p) then begin
ShowMessage('Found it!: ' + p.FullName);
end;
finally
for p in Dic.Values do
p.Free;
//Also free Values and KeyCollection
//other wise you have a memoryleak
//Is this a bug?
Dic.Values.Free;
Dic.Keys.Free;
//Free the dictionary
Dic.Free;
end;
샘플에 대한 자세한 내용은 아래 URL을 참고 하시기 바랍니다.
http://beensoft.blogspot.com/2008/09/simple-generic-dictionary-tdictionary.html%EF%BB%BF
제너릭을 지원하고 쉬운 사용이 가능하기 때문에
유용한 클래스 이지만 메모리 관리가 불편하다는
단점이 있네요. 상속을 받아 메모리 누수를
해결 해서 사용하면 아주 편리하지 않을까 생각합니다.
C#에서 사용되는 것은 봤는데
델파이2009에서도 추가가 되어 있어 참 반가웠습니다.
hash table을 써도 무관하겠지만 제너릭을
지원한다는데에 매력이 있는 것 같습니다
Delphi 2009 에서 Generic이 추가되면서
유용한 클래스들이 추가되었다.
특히나 특정 Key와 쌍을 이루는 값을 저장할때
TDictionary는 참 유용하게 쓰인다.
일반 데이터 형을 보관할 때는 상관이 없으나
Class를 보관할때는 메모리 해제에 주의해야 한다.
uses
Generics.Collections;
type
TTempKey = class
end;
TTempValue = class end;
1. TDictionary
procedure TForm2.Button1Click(Sender: TObject);
var
Dic: TDictionary<Integer,TTempValue>;
Key: Integer;
begin
Dic := TDictionary<Integer,TTempValue>.Create;
try
Dic.Add( 1, TTempValue.Create );
for Key in Dic.Keys do
Dic.Items[Key].Free;
finally
Dic.Free;
end;
end;
Key와 매칭되는 Value를 저장할 수 있다.
여기서는 Key의 형을 Integer, Value의 형은
TTempValue 클래스로 설정했다.
Dic만 해제하면 TDictonary의 Values에
저장된 TTempValue 인스턴스가 붕 떠서 Memory Leak이 발생한다.
반드시 Dic를 해제하기 전에 Dic의 아이템들을 해제해야 한다.
2. TObjectDictionary
예전부터 Contnrs 유닛에 있던 TObjectList와 비슷하다.
생성시에 OwnsObject를 True로 설정해서
자동으로 아이템의 메모리를 해제했던 기억이 있을 것이다.
(1) Key와 Value 가 모두 Class형인 경우
procedure TForm2.Button2Click(Sender: TObject);
var
Dic: TObjectDictionary<TTempKey,TTempValue>;
begin
Dic := TObjectDictionary<TTempKey,TTempValue>.Create( [doOwnsKeys, doOwnsValues] );
try
Dic.Add( TTempKey.Create, TTempValue.Create );
finally
Dic.Free;
end;
end;
인스턴스 생성시에 생성자의 인자를 보면
TDictionaryOwnerships라는 집합형을 넘긴다.
TObjectList의 OwnsObject를 생각하면 된다.
Key와 Value가 모두 클래스 형이므로
둘다 소유하는 것으로 설정했다.
(2) Value만 Class형인 경우
procedure TForm2.Button3Click(Sender: TObject);
var
Dic: TObjectDictionary<Integer,TTempValue>;
begin
Dic := TObjectDictionary<Integer,TTempValue>.Create( [doOwnsValues] );
try
Dic.Add( 1, TTempValue.Create );
finally
Dic.Free;
end;
end;
Value만 클래스 형인 경우 Key를 소유하라고
doOwnsKeys를 설정하면 익셉션이 발생한다.
익셉션 클래스는 EInvalidCast, 메시지는 Invalid class typecast.
unit Unit3;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils,
System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Generics.Collections, Vcl.StdCtrls;
type
TForm3 = class(TForm)
Memo1: TMemo;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
type
TPerson = class(Tobject)
public
ID : integer;
OtherRef : String;
Name : string;
constructor Create(ID : integer; OtherREf, Name : STring);
function Equals(Obj : TObject): Boolean; override;
function GetHashCode : Integer; override;
end;
var
Form3: TForm3;
implementation
{$R *.dfm}
{ TPerson }
constructor TPerson.Create(ID: integer; OtherREf, Name: STring);
begin
Self.ID := ID;
Self.OtherRef := OtherREf;
Self.Name := Name;
end;
procedure TForm3.Button1Click(Sender: TObject);
var
D : TObjectDictionary<TPerson,String>;
P : TPerson;
begin
D := TObjectDictionary<TPerson,string>.Create([doOwnsKeys]);
try
D.Add(TPerson.Create(1,'B97', 'Bob'), 'Info about Bob');
D.Add(TPerson.Create(2,'A32', 'Alice'), 'Info about Alice');
D.Add(TPerson.Create(3,'C16', 'Charles'), 'Info about Charles');
P := TPerson.Create(1,'B12', 'Bill');
Memo1.Lines.Add(D[P]);
P.Free;
finally
D.Free;
end;
end;
function TPerson.Equals(Obj: TObject): Boolean;
begin
if Obj = nil then
Result := False
else
Result := (Obj is TPerson) and ((Obj as TPerson).ID = ID) and ((Obj as TPerson).OtherRef = OtherRef);
end;
function TPerson.GetHashCode: Integer;
begin
Result := OtherREf.GetHashCode xor ID;
end;
procedure TForm3.Button2Click(Sender: TObject);
var
iDictionary: TDictionary<string, string>;
begin
iDictionary := TDictionary<string, string>.Create;
try
iDictionary.Add('Monday','TEll mey I don ''t like these');
iDictionary.Add('Tuesday','Is full of grace');
iDictionary.Add('Wednesday','Hump Day!!!');
Memo1.Lines.Add(iDictionary['Monday'])
finally
iDictionary.Free;
end;
end;
end.
'Delphi > 클래스' 카테고리의 다른 글
델파이 쓰레드(Thread)의 기초 (0) | 2021.08.07 |
---|---|
델파이 레코드 클래스 성능 비교 (0) | 2021.08.05 |
델파이 클래스 메소드 사용방법 (0) | 2021.08.03 |
델파이의 클래스 헬퍼(helper) (0) | 2021.08.02 |
델파이 쓰레드 사용법 (0) | 2021.05.21 |
댓글