当记录超出范围时,引用未记录的记录中的对象

Dsm*_*Dsm 2 delphi

我有一个记录,其中包含我认为是指向引用计数对象的指针.我希望如果我在记录中创建引用计数对象,当记录超出范围时,对象的引用计数将降为零,并且对象将被销毁.但这似乎并非如此.这是最小代码示例.我的表格恰好有一些面板和备忘录,但只有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.
Run Code Online (Sandbox Code Playgroud)

我承认我并不真正理解引用计数是如何工作的,尽管我理解这个原理.我错过了什么?我是否期望太多,如果是这样,有没有办法避免内存泄漏,不是在这种特定情况下(显然我可以在退出时销毁UserData)但一般来说,因为记录不支持析构函数.

Dav*_*nan 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.
Run Code Online (Sandbox Code Playgroud)

这个程序不泄漏.将记录类型中的变量声明更改为,UserData: TUserData并返回泄漏.