我有一条记录,其中包含我认为是指向引用计数对象的指针。我希望如果我在记录中创建引用计数对象,当记录超出范围时,对象的引用计数将降为零,并且对象将被销毁。但这似乎并非如此。这是最小代码示例。我的表格碰巧有一些面板和备忘录,但只有TButton(特别是Button1Click)很重要。
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;
type
TUserData = class( TInterfacedObject )
public
AData : integer;
constructor Create;
destructor Destroy; override;
end;
TTestRec = Record
AField : integer;
UserData : TUserData;
End;
TForm4 = class(TForm)
Panel1: TPanel;
Panel2: TPanel;
Panel3: TPanel;
Memo1: TMemo;
Button1: TButton;
procedure FormShow(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form4: TForm4;
implementation
{$R *.dfm}
procedure TForm4.Button1Click(Sender: TObject);
var
iRec : TTestRec;
begin
iRec.UserData := TUserData.Create;
// stop too much optimisation
Button1.Caption := IntToStr( iRec.UserData.AData );
end; // I would expect TTestRec and hence TTestRec.UserData to go out of scope here
procedure TForm4.FormShow(Sender: TObject);
begin
// show leaks on exit
ReportMemoryLeaksOnShutdown := TRUE;
end;
{ TUserData }
constructor TUserData.Create;
begin
inherited Create;
AData := 4;
end;
destructor TUserData.Destroy;
begin
inherited;
end;
end.
我承认我并不真正理解引用计数是如何工作的,尽管我理解这个原理。我错过了什么?我是否期望太多,如果是这样,有没有办法避免内存泄漏,不是在这种特定情况下(显然我可以在退出时销毁UserData)但一般来说,因为记录不支持析构函数。
答案 0 :(得分:6)
自动引用计数通过接口变量执行。你什么都没有。而不是类型TUserData
的变量,您需要一个作为接口的变量。
你可以在这里使用IInterface
,但那会有点无用。因此,您应该定义一个接口,该接口公开您需要对象支持的公共功能,然后让您的类实现该接口。
这个程序证明了我的意思:
type
IUserData = interface
['{BA2B50F5-9151-4F84-94C8-6043464EC059}']
function GetData: Integer;
procedure SetData(Value: Integer);
property Data: Integer read GetData write SetData;
end;
TUserData = class(TInterfacedObject, IUserData)
private
FData: Integer;
function GetData: Integer;
procedure SetData(Value: Integer);
end;
function TUserData.GetData: Integer;
begin
Result := FData;
end;
procedure TUserData.SetData(Value: Integer);
begin
FData := Value;
end;
type
TTestRec = record
UserData: IUserData;
end;
procedure Main;
var
iRec: TTestRec;
begin
iRec.UserData := TUserData.Create;
end;
begin
Main;
ReportMemoryLeaksOnShutdown := True;
end.
此程序不泄漏。将记录类型中的变量声明更改为UserData: TUserData
,并返回泄漏。