Delphi中释放介绍

在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.
Delphi中,`TArrayByte`是一个动态数组,通常用于存储字节数据。当你不再需要`TArrayByte`变量时,应当正确地释放其占用的内存资源,以防内存泄漏。对于动态分配的`TArrayByte`,你可以通过以下几个步骤释放: 1. 首先,确保`TArrayByte`不是静态的,如果是静态数组,不需要手动释放,因为静态数组由 Delphi 管理。 2. 使用`Clear()`方法清空数组内容。这将释放已分配给当前元素的所有内存,但不会改变数组本身的大小。 ```delphi var MyByteArray: TArrayByte; begin // ... 使用 MyByteArray // 清除数组内容 MyByteArray.Clear(); // 如果你想完全释放内存,可以设置数组长度为0,但这并不总是必要的 // 因为 Clear() 之后,数组实际上已经释放了 // MyByteArray.Length := 0; // 如果是动态创建的数组,考虑使用 SetLength 或者 FreeMemory // 如果有其他分配的内存(如通过 `^byte` 指针),记得单独释放 end; ``` 3. 如果是通过`New`或`AllocMem`等动态分配内存的方式创建的`TArrayByte`,并且你确实想释放所占内存,可以在`Free`前设置`Size`为0,然后使用`Free`: ```delphi if Assigned(MyByteArray) then begin MyByteArray.Size := 0; // 设置大小为0以便释放内存 FreeMemory(MyByteArray); // 释放内存 end; ``` 记得在使用完`TArrayByte`后始终检查是否有必要进行释放操作,特别是当它是由用户输入或其他不确定来源初始化的时候。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值