在delphi中,有些函数或者设置会使对象自动释放,此时如果在次释放会发生野指针的现象,导致莫名的错误。
下面介绍几种经常见到的释放规则。
(一)、使用 TObjectList
procedure TForm1.Button1Click(Sender: TObject);
var
list: TObjectList;
i: Integer;
btn: TButton;
begin
list := TObjectList.Create;
for i := 0 to 6 do
begin
btn := TButton.Create(Self);
with btn do begin
Caption := Format('Btn %d', [i+1]);
Parent := Self;
end;
list.Add(btn);
end;
ShowMessage('TObjectList 释放时, 会同时释放其中的对象');
list.Free;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
list: TList;
i: Integer;
btn: TButton;
begin
list := TList.Create;
for i := 0 to 6 do
begin
btn := TButton.Create(Self);
with btn do begin
Caption := Format('Btn %d', [i+1]);
Parent := Self;
end;
list.Add(btn);
end;
ShowMessage('TList 释放后, 其中的对象并未释放');
list.Free;
end;
(二)使用 TObjectList<T>
procedure TForm1.Button1Click(Sender: TObject);
var
list: TObjectList<TButton>;
i: Integer;
btn: TButton;
begin
list := TObjectList<TButton>.Create;
for i := 0 to 6 do
begin
btn := TButton.Create(Self);
with btn do begin
Caption := Format('Btn %d', [i+1]);
Parent := Self;
end;
list.Add(btn);
end;
ShowMessage('TObjectList 释放时, 会同时释放其中的对象');
list.Free;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
list: TList<TButton>;
i: Integer;
btn: TButton;
begin
list := TList<TButton>.Create;
for i := 0 to 6 do
begin
btn := TButton.Create(Self);
with btn do begin
Caption := Format('Btn %d', [i+1]);
Parent := Self;
end;
list.Add(btn);
end;
ShowMessage('TList 释放后, 其中的对象并未释放');
list.Free;
end;
(三)使用记录而不是记录指针
{假如某个函数的参数需要一个结构指针}
function Area(rect: PRect): Integer;
begin
Result := rect.Width * rect.Height;
end;
{直接声明指针并分配空间后需手动释放}
procedure TForm1.Button1Click(Sender: TObject);
var
P: PRect;
begin
New(P);
P^ := Rect(10, 10, 60, 50);
ShowMessage(IntToStr(Area(P))); //2000
Dispose(P);
end;
procedure TForm1.Button2Click(Sender: TObject);
var
R: TRect;
begin
R := Rect(10, 10, 60, 50);
ShowMessage(IntToStr(Area(@R))); //2000
end;
(四)使用动态数组
procedure TForm1.Button1Click(Sender: TObject);
var
arr: Array of string;
i: Integer;
s: string;
begin
for i := 0 to 3 do
begin
SetLength(arr, Length(arr)+1);
arr[High(arr)] := StringOfChar(Char(i + 1), 3);
end;
for s in arr do ShowMessage(s);
end;
procedure TForm1.Button2Click(Sender: TObject);
var
arr: TArray<string>;
i: Integer;
s: string;
begin
for i := 0 to 23 do
begin
SetLength(arr, Length(arr)+1);
arr[High(arr)] := StringOfChar(Char(i + 1), 3);
end;
for s in arr do ShowMessage(s);
end;
(五)在 initialization 中建立、在 finalization 中释放
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
var
List: TStringList;
procedure TForm1.Button1Click(Sender: TObject);
begin
List.Clear;
List.Add('WanYi');
ShowMessage(List.Text);
end;
initialization
List := TStringList.Create;
finalization
List.Free;
end.
(六)使用记录(现在的记录支持使用方法)
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
//
TBase = record
private
FName: string;
procedure SetName(const AName: string);
public
constructor Create(const AName: string);
property Name: string read FName write SetName;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
X: TBase;
begin
X := TBase.Create('Test');
ShowMessage(X.Name);
X.Name := 'Test1';
ShowMessage(X.Name);
{X 在此自动释放}
end;
{ TBase }
constructor TBase.Create(const AName: string);
begin
FName := AName;
end;
procedure TBase.SetName(const AName: string);
begin
FName := AName;
end;
end.
(七)使用接口
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
//
IBase = Interface
function GetName: string;
procedure SetName(const AName: string);
property Name: string read GetName write SetName;
end;
//
TBase = class(TInterfacedObject, IBase)
private
FName: string;
protected
function GetName: string;
procedure SetName(const AName: string);
public
constructor Create(const AName: string);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
X: IBase;
begin
X := TBase.Create('Test');
ShowMessage(X.Name);
X.Name := 'Test1;
ShowMessage(X.Name);
{X 在此自动释放}
end;
{ TBase }
constructor TBase.Create(const AName: string);
begin
FName := AName;
end;
function TBase.GetName: string;
begin
Result := FName;
end;
procedure TBase.SetName(const AName: string);
begin
FName := AName;
end;
end.
476

被折叠的 条评论
为什么被折叠?



