델파이에서 모든 클래스는 사실상 포인트로 다루어집니다.
var
list : TStringList;
list := TStringList.Create;
이렇게 되면
list 는 TStringList의 인스턴스에 대한 포인트 역할을 합니다.
문법상 뚜렷하게 포인트와 객체의 인스턴스를 구분짓는 C++과는 달리
델파이에서는 내부적으로는 포인트로 알아서 처리되지만 겉보기는 그냥 실제 객체로 다루고 있는 것처럼 보입니다.
그런데 델파이 인스턴스 만들때 제약 사항이 있습니다.
바로 클래스의 인스턴스는 모두 힙에 생성되어야 하며, 스택에는 생성될 수 없다는 것입니다.
이로 인해 인스턴스를 Create 해주면 짝을 맞춰 명시적으로 Free 해줘야 하는 수고를 해야 합니다.
이는 델파이 사용자라면 늘상 하는 일이니 아무런 불편이 되지 않을지 모릅니다.
그러나 C++를 쓰던 입장에서 보면 대단히 불편한 부분이 아닐 수 없습니다.
스택에 인스턴스를 생성하지 못하는 것은 컴파일러 구조상 어쩔수 없다고 한다면,
최소한 명시적으로 객체를 해제해주는 것만은 생략할 수 있지 않을까 해서 예전에 자료를 찾아 봤는데,
마침 IInterface의 인스턴스가 지역 객체로 동작하는 특성을 이용해서, 구현한 사례가 있더군요.
JCL에 있던 Guard를 간략하게 바꾼, 델마당의 프리맨님이 올린 Guard 가 그것입니다.
출처:
http://www.delmadang.com/community/bbs_view.asp?bbsNo=3&bbsCat=0&st=S&keyword=guard&indx=196963&keyword1=guard&keyword2=&page=1
C++에서는 이러한 것을 보통 스마트포인트 또는 AutoPtr 이라고 하므로,
직관성을 높이기 위해 명칭을 AutoPtr 로 변경했습니다.
델파이 프로그램 때 이를 적용하면 한결 편리합니다. 객체의 해제에 대한 신경을 안써도 되기 때문입니다.
예제.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, uAutoPtr, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Memo2: TMemo;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
list: TStringList;
list2: TStringList;
begin
list := TStringList.Create;
AutoPtr(list2, TStringList.Create);
try
list.Add('우리는 민족중흥의');
list.Add('역사적 사명을 띄고 이땅에 태어났다.');
Memo1.Lines := list;
list2.Add('조상의 빛난 얼을 오늘에 되살려');
list2.Add('IT 최강국을 만들자.');
Memo2.Lines := list2;
finally
list.Free;
end;
// list2는 자동 free 된다.
// 위처럼 try finally 블럭을 써서 명시적으로 Free 해줘야 하는 수고를 안해도 되며
// 이 함수를 어떤 식으로 벗어나던지 벗어날때 자동으로 Free 된다.
end;
end.
AutoPtr 유닛 소스
---------------
unit uAutoPtr;
interface
function AutoPtr(out Reference; Instance: TObject): IUnknown;
implementation
type
TGuardObject = class(TInterfacedObject)
private
FInstance: TObject;
public
constructor Create(Instance: TObject);
destructor Destroy; override;
end;
{ TGuardObject }
constructor TGuardObject.Create(Instance: TObject);
begin
FInstance:= Instance;
end;
destructor TGuardObject.Destroy;
begin
FInstance.Free;
inherited;
end;
function AutoPtr(out Reference; Instance: TObject): IUnknown;
begin
Result := TGuardObject.Create(Instance);
TObject(Reference) := Instance;
end;
end.
정말 유용하네요 ^^ 코드도 깔끔해지구 감사합니다.