I have a little problem. As the title says I want to release an object whose class implements an interface, however I get an error "invalid pointer operation".
My Interface:
Interface
Type
// An interface definition
IMessageEvents = Interface(IInterface)
['{BD27EFC6-CC9A-437A-A8B8-16F722518836}']
Procedure messageReceived(messageData: String);
End;
Implementation
My Class:
Type
TChatManager = Class(TInterfacedObject, IMessageEvents)
Private
Protected
Procedure messageReceived(messageData: String); Overload;
Public
Constructor Create; Overload;
Destructor Destroy; Override;
Procedure connect;
Procedure disconnect;
End;
Implementation
Constructor TChatManager.Create;
Begin
{ ....... }
End;
Procedure TChatManager.connect;
Begin
{ ....... }
End;
Procedure TChatManager.disconnect;
Begin
{ ....... }
End;
Procedure TChatManager.messageReceived(messageData: String);
Begin
{ ....... }
End;
Destructor TChatManager.Destroy;
Begin
Inherited Destroy;
End;
My Code:
self.chatMng := TChatManager.Create;
self.chatMng.Free;
Can anyone tell me what I'm doing wrong? Thanks in advance.
It would appear that chatMng
is of type TChatManager
. That can be deduced by the fact that you assign TChatManager.Create
to it, and call Free
on it.
However, TChatManager
derives from TInterfacedObject
. That means that its lifetime is controlled by the references that are taken to its interfaces. When the final reference is released, the object is destroyed.
The rule of thumb is that if you derive from TInterfacedObject
then you must never take a reference to the object other than through an interface variable.
Steps to correct your code:
- Change
chatMng
to be of type IMessageEvents
.
- Remove the call to
chatMng.Free
which the compiler will object to in any case.
He must not be showing us all the code...because what he shows should not cause a GPF...you can create a TInterfacedObject and free it...if you don't get a reference to it...but If you get a Reference you are no longer in charge of freeing it...
Here's the Interface
unit Unit3;
Interface
uses
Classes, SysUtils;
Type
// An interface definition
IMessageEvents = Interface(IInterface)
['{BD27EFC6-CC9A-437A-A8B8-16F722518836}']
Procedure messageReceived(messageData: String);
End;
Type
TChatManager = Class(TInterfacedObject, IMessageEvents)
Private
FStrings: TStrings;
Protected
Procedure messageReceived(messageData: String); Overload;
procedure UpdateStatus(aString: string);
Public
Constructor Create(aStrings: TStrings);
Destructor Destroy; Override;
Procedure connect;
Procedure disconnect;
End;
Implementation
Constructor TChatManager.Create(aStrings: TStrings);
Begin
{ ....... }
FStrings := aStrings;
UpdateStatus('Created');
Connect;
End;
Procedure TChatManager.connect;
Begin
{ ....... }
UpdateStatus('Connected');
End;
Procedure TChatManager.disconnect;
Begin
{ ....... }
UpdateStatus('DisConnected');
End;
Procedure TChatManager.messageReceived(messageData: String);
Begin
{ ....... }
UpdateStatus('Message Received');
UpdateStatus(messageData);
End;
procedure TChatManager.UpdateStatus(aString: string);
begin
FStrings.Add(aString);
FStrings.Add('RefCount: '+ IntToStr(Self.RefCount));
end;
Destructor TChatManager.Destroy;
Begin
Disconnect;
UpdateStatus('Destroyed');
Inherited Destroy;
End;
end.
Here's the form
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, unit3, StdCtrls;
type
TForm2 = class(TForm)
Button1: TButton;
Memo1: TMemo;
Button2: TButton;
Button3: TButton;
Button4: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
{ Private declarations }
chatMng: TChatManager;
iChatMng: IMessageEvents;
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
type
THackManager= class(TChatManager);
procedure TForm2.Button1Click(Sender: TObject);
begin
chatMng := TChatManager.Create(Memo1.Lines);
THackManager(ChatMng).messageReceived('Hello World from Button1');
chatMng.Free;
end;
procedure TForm2.Button2Click(Sender: TObject);
begin
iChatMng := TChatManager.Create(Memo1.Lines);
iChatMng.messageReceived('Hello World from Button2');
iChatMng := nil;
end;
procedure TForm2.Button3Click(Sender: TObject);
begin
ChatMng := TChatManager.Create(Memo1.Lines);
(ChatMng as IMessageEvents).messageReceived('Hello World from Button3');
//you can't call ChatMng...it's gone bye bye...
//ChatMng.Free; //this will cause a GPF if you call free
end;
procedure TForm2.Button4Click(Sender: TObject);
var
a_IChatMng: IMessageEvents;
begin
ChatMng := TChatManager.Create(Memo1.Lines);
a_IChatMng := chatMng;
(ChatMng as IMessageEvents).messageReceived('Hello World from Button4');
a_IChatMng.messageReceived('Hello World again from Button4');
//ChatMng.Free; //this will cause a GPF if you call free
end;
end.
Here's the dfm
object Form2: TForm2
Left = 326
Top = 94
Caption = 'Form2'
ClientHeight = 292
ClientWidth = 581
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 40
Top = 200
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
object Memo1: TMemo
Left = 40
Top = 32
Width = 411
Height = 129
TabOrder = 1
end
object Button2: TButton
Left = 160
Top = 200
Width = 75
Height = 25
Caption = 'Button2'
TabOrder = 2
OnClick = Button2Click
end
object Button3: TButton
Left = 272
Top = 200
Width = 75
Height = 25
Caption = 'Button3'
TabOrder = 3
OnClick = Button3Click
end
object Button4: TButton
Left = 376
Top = 200
Width = 75
Height = 25
Caption = 'Button4'
TabOrder = 4
OnClick = Button4Click
end
end