【问题标题】:Fails freeing Interface implemented class [duplicate]无法释放接口实现的类[重复]
【发布时间】:2014-01-10 23:07:01
【问题描述】:

我之前开过一个类似的话题,但是我在尝试释放类实例时没有明确的错误原因“invalid pointer operation”。现在我已经知道原因了,所以我开一个新话题,揭露问题。

所以这个错误的原因是在实例化类 ChatClient 并将类本身的实例 (TChatManager) 作为参数传递时。可能问题与 TChatManager 类对接口的实现有关。

界面:

Type
  // An interface definition
  IMessageEvents = Interface(IInterface)
    ['{BD27EFC6-CC9A-437A-A8B8-16F722518836}']

    Procedure messageReceived(messageData: String);
  End;

类 TChatManager:

Type
  TChatManager = Class(TInterfacedObject, IMessageEvents)
  Private
    cChatClient: TChatClient;
  Protected
    Procedure messageReceived(messageData: String); Overload;
  Public
    Constructor Create; Overload;
    Destructor Destroy; Override;
  End;

Implementation

Constructor TChatManager.Create;
Begin
  Inherited Create;
  self.cChatClient := TChatClient.Create(self); // self class instance as parameter
End;

Procedure TChatManager.messageReceived(messageData: String);
Begin

End;

Destructor TChatManager.Destroy;
Begin
  Inherited Destroy;
End;

TChatClient 类:

Type
  TChatClient = Class(TObject)
  Private
    iMsgEvents: IMessageEvents;
  Protected
  Public
    Constructor Create(iMsgEvents: IMessageEvents); Overload;
    Destructor Destroy; Override;
  End;

Implementation

Constructor TChatClient.Create(iMsgEvents: IMessageEvents);
Begin
  Inherited Create;
  self.iMsgEvents := iMsgEvents;
End;

Destructor TChatClient.Destroy;
Begin
  Inherited Destroy;
End;

主要:

cChatManager: TChatManager;
self.cChatManager := TChatManager.Create;
self.cChatManager.Free; // Failed

任何人都可以解释我实施的不好吗?谢谢。

注意:类不完整,我删除了一些释放对象的方法等...

问候。

【问题讨论】:

  • @LU RD 感谢您的回复。类不完整,我删除了释放对象的方法。但问题不存在。
  • @David,是的,我知道,实际上在第一行中我已经说过我之前发布过类似的问题。事实是,虽然问题解决了,但我并没有弄清楚到底是什么导致了错误,所以我不得不开一个新话题。
  • 我想我已经解释过了。也许还不够好。关键是接口引用控制生命周期。因此,您必须停止持有接口引用以外的引用。
  • @David 是的,我知道,但我留下了一些疑问。我必须学习更多。谢谢。

标签: delphi class interface free


【解决方案1】:

你的问题的答案是TInterfacedObject的以下方法:

procedure TInterfacedObject.BeforeDestruction;
begin
  if RefCount <> 0 then
    Error(reInvalidPtr);
end;

您的代码正在销毁具有非零 RefCount 字段的 TChatManager 实例,因为它被 TChatClient 实例引用。


OP 代码无法修复,应该重新设计,因为在当前形式中,TChatManager 实例应该在TChatClient 析构函数中销毁(通过设置iMsgEvents:= nil),这很奇怪! :)

【讨论】:

  • 这就是引发异常的原因。真正的问题是赋值给cChatManager,一个TChatManager类型的变量,导致引用计数生命周期管理的颠覆。
  • @user246408 谢谢,现在我明白为什么会出现这个错误了。大卫也感谢您的回复。
  • @DavidHeffernan - 这是个好问题;肯定混合对象和接口引用是不好的设计,但发现错误本身是有趣的事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-17
  • 2021-05-02
  • 2019-04-03
  • 1970-01-01
  • 2014-04-12
  • 2023-03-23
  • 1970-01-01
相关资源
最近更新 更多