【问题标题】:delphi 2009, interface already releaseddelphi 2009,界面已经发布
【发布时间】:2013-08-12 16:00:58
【问题描述】:

我想要有接口的特殊记录。

而且,接口有子接口和一些类。所以,需要自动释放。 但是,记录中的接口已经发布了。

需要帮助,为什么引用计数不匹配?

我尝试下一个代码...

//--------------------------------------------- ----------------------

type
  IIn = interface
    procedure SetValue(v : string);
    function AsString() : string;
    function GetChild() : IIn;
  end;

  RIn = record
    FIn : IIn;

    procedure SetInterface(intf : IIn);
    procedure SetValue(v : string);
    function AsString() : string;
    function GetChild() : RIn;
  end;

  TIn = class(TInterfacedObject, IIn)
  private
    FChild : IIn;
    FValue : string;
  public
    procedure SetValue(v : string);
    function AsString() : string;
    function GetChild() : IIn;
  end;

//--------------------------------------------- ----------------------

procedure RIn.SetInterface(intf : IIn);
begin
  FIn := intf;
end;

function RIn.GetChild() : RIn;
var
  childInterface : IIn;
begin
  if FIn = nil then FIn := TIn.Create();
  childInterface := FIn.GetChild();

  Result.SetInterface( childInterface );
end;

procedure RIn.SetValue(v : string);
begin
  if FIn = nil then FIn := TIn.Create();
  FIn.SetValue(v);
end;

function RIn.AsString() : string;
begin
  if FIn = nil then FIn := TIn.Create();

  Result := FIn.AsString();
end;

function RIn.GetRefCnt() : integer;
begin
  if FIn = nil then FIn := TIn.Create();

  Result := FIn.GetRefCnt();
end;

procedure TIn.SetValue(v : string);
begin
  FValue := v;
end;

function TIn.AsString() : string;
begin
  Result := FValue;
end;

function TIn.GetChild() : IIn;
begin
  if FChild = nil then FChild := TIn.Create();

  Result := FChild;
end;

//--------------------------------------------- ----------------------

// global var
var
  test : RIn;

// test procedure 1
procedure test1;
begin
  test.GetChild().SetValue('test...');
end;

// test procedure 2
procedure test2;
begin
  ShowMessage(   test.GetChild().AsString    );    <----- Error!! child interface is already released..
end;

【问题讨论】:

  • 您需要显示 TIn.GetChild 的代码。我猜这会返回 TIn.FChild 并且从未创建过并且为零。这段代码似乎有很多令人困惑的部分。您可能想描述您正在尝试做什么以获得更好的答案。把一个接口放在一个具有相同功能的记录中只是自找麻烦。
  • 函数 TIn.GetChild() : IIn;如果 FChild = nil 则开始 FChild := TIn.Create();结果:= FChild;结尾;
  • 看起来像 Delphi 2009 的错误; test1 中可能有错误的最终确定代码。不能多说,需要时间调试。
  • 代码在 Delphi-XE2 中工作。

标签: delphi memory-management interface record


【解决方案1】:

这是 Delphi 2009 引用计数错误。我稍微修改了您的代码以输出引用计数器:

program Bug2009;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  IIn = interface
    procedure SetValue(v : string);
    function AsString() : string;
    function GetChild() : IIn;
  end;

  RIn = record
    FIn : IIn;

    procedure SetInterface(intf : IIn);
    procedure SetValue(v : string);
    function AsString() : string;
    function GetChild() : RIn;
  end;

  TIn = class(TInterfacedObject, IIn)
  private
    FChild : IIn;
    FValue : string;
  public
    procedure SetValue(v : string);
    function AsString() : string;
    function GetChild() : IIn;
  end;

procedure RIn.SetInterface(intf : IIn);
begin
  FIn := intf;
end;

function RIn.GetChild() : RIn;
var
  childInterface : IIn;
begin
  if FIn = nil then FIn := TIn.Create();
  childInterface := FIn.GetChild();
  Result.SetInterface( childInterface );
end;

procedure RIn.SetValue(v : string);
begin
  if FIn = nil then FIn := TIn.Create();
  FIn.SetValue(v);
end;

function RIn.AsString() : string;
begin
  if FIn = nil then FIn := TIn.Create();

  Result := FIn.AsString();
end;

procedure TIn.SetValue(v : string);
begin
  FValue := v;
end;

function TIn.AsString() : string;
begin
  Result := FValue;
end;

function TIn.GetChild() : IIn;
begin
  if FChild = nil then FChild := TIn.Create();
    Writeln(FChild._AddRef - 1);
    FChild._Release;
  Result := FChild;
end;

// global var
var
  test : RIn;

// test procedure 1
procedure test1;
begin
  test.GetChild().SetValue('test...');
end;

// test procedure 2
procedure test2;
begin
  Writeln(   test.GetChild().AsString    );   // <----- Error!! child interface is already released..
end;

begin
  try
    test1;
    test2;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  readln;
end.

输出(Delphi 2009)是

对 Delphi XE 输出的相同测试

查看不同的参考计数器值

【讨论】:

  • +1。我认为这是qc.embarcadero.com/wc/qcmain.aspx?d=90482 的一种表现您是否验证了您的代码可以在比Delphi 2009 更年轻的Delphi 版本中工作?请告诉我们。
  • @JeroenWiertPluimers - 手头没有更多的 Delphi 版本,任何人都可以在我的答案中运行测试,看看它是否输出错误的 0 refcounter。
  • 在 Delphi XE、XE2 和 XE4 中运行良好。现在希望有 Delphi 2010 的人可以检查一下。
猜你喜欢
  • 1970-01-01
  • 2011-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-10
  • 2011-07-12
  • 2011-05-28
  • 1970-01-01
相关资源
最近更新 更多