Delphi 无法释放接口实现的类
我以前打开过一个类似的主题,但在尝试释放类实例时,没有明确的原因导致错误“无效指针操作”。现在我已经知道了原因,所以我打开了一个新的话题,来揭露这个问题 因此,此错误的原因是在实例化类ChatClient并将类本身的实例(TChatManager)作为参数传递时。问题可能与类TChatManager到接口的实现有关 界面:Delphi 无法释放接口实现的类,delphi,class,interface,free,Delphi,Class,Interface,Free,我以前打开过一个类似的主题,但在尝试释放类实例时,没有明确的原因导致错误“无效指针操作”。现在我已经知道了原因,所以我打开了一个新的话题,来揭露这个问题 因此,此错误的原因是在实例化类ChatClient并将类本身的实例(TChatManager)作为参数传递时。问题可能与类TChatManager到接口的实现有关 界面: Type // An interface definition IMessageEvents = Interface(IInterface) ['{BD27E
Type
// An interface definition
IMessageEvents = Interface(IInterface)
['{BD27EFC6-CC9A-437A-A8B8-16F722518836}']
Procedure messageReceived(messageData: String);
End;
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;
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
班级管理者:
Type
// An interface definition
IMessageEvents = Interface(IInterface)
['{BD27EFC6-CC9A-437A-A8B8-16F722518836}']
Procedure messageReceived(messageData: String);
End;
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;
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
类TChatClient:
Type
// An interface definition
IMessageEvents = Interface(IInterface)
['{BD27EFC6-CC9A-437A-A8B8-16F722518836}']
Procedure messageReceived(messageData: String);
End;
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;
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
Main:
Type
// An interface definition
IMessageEvents = Interface(IInterface)
['{BD27EFC6-CC9A-437A-A8B8-16F722518836}']
Procedure messageReceived(messageData: String);
End;
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;
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
有人能解释我在做什么吗?谢谢
注意:类不完整,我删除了一些释放对象的方法,等等
问候。您的问题的答案是以下
TInterfacedObject
的方法:
procedure TInterfacedObject.BeforeDestruction;
begin
if RefCount <> 0 then
Error(reInvalidPtr);
end;
销毁前的程序TInterfacedObject;
开始
如果RefCount为0,则
错误(reInvalidPtr);
结束;
您的代码正在销毁具有非零RefCount
字段的TChatManager
实例,因为它被TChatClient
实例引用
OP代码无法修复,应该重新设计,因为在当前形式中,
TChatManager
实例应该在TChatClient
析构函数中销毁(通过设置iMsgEvents:=nil
),这很奇怪!) 您的问题的答案是以下TInterfacedObject
的方法:
procedure TInterfacedObject.BeforeDestruction;
begin
if RefCount <> 0 then
Error(reInvalidPtr);
end;
销毁前的程序TInterfacedObject;
开始
如果RefCount为0,则
错误(reInvalidPtr);
结束;
您的代码正在销毁具有非零RefCount
字段的TChatManager
实例,因为它被TChatClient
实例引用
OP代码无法修复,应该重新设计,因为在当前形式中,
TChatManager
实例应该在TChatClient
析构函数中销毁(通过设置iMsgEvents:=nil
),这很奇怪!) @LU-RD感谢您的回复。类不完整,我删除了释放对象的方法。但是问题不在那里。@David,是的,我知道,事实上在第一行我已经说过我以前也发布过类似的问题。事实是,虽然问题已经解决了,但我不清楚到底是什么导致了错误,所以我不得不打开一个新的话题。我想我已经解释过了。也许还不够好。关键是接口引用控制生命周期。你必须停止持有接口引用以外的引用。@David是的,我知道,但我留下了一些疑问。我必须学习更多。谢谢。@LU RD感谢您的回复。类不完整,我删除了释放对象的方法。但是问题不在那里。@David,是的,我知道,事实上在第一行我已经说过我以前也发布过类似的问题。事实是,虽然问题已经解决了,但我不清楚到底是什么导致了错误,所以我不得不打开一个新的话题。我想我已经解释过了。也许还不够好。关键是接口引用控制生命周期。你必须停止持有接口引用以外的引用。@David是的,我知道,但我留下了一些疑问。我必须学习更多。谢谢你。这就是引起例外的原因。真正的问题是将cChatManager
类型的变量TChatManager
@user246408分配给cChatManager
,导致引用计数的生存期管理被破坏。谢谢,现在我明白了出现此错误的原因。大卫也谢谢你的回答。@DavidHeffernan-这是个好问题;当然,混合对象和接口引用是一种糟糕的设计,但找到bug本身却是一件有趣的事情。这就是引发异常的原因。真正的问题是将cChatManager
类型的变量TChatManager
@user246408分配给cChatManager
,导致引用计数的生存期管理被破坏。谢谢,现在我明白了出现此错误的原因。大卫也谢谢你的回答。@DavidHeffernan-这是个好问题;当然,混合使用对象和接口引用是糟糕的设计,但找到bug本身是一件有趣的事情。