2

Please take a look at the following Free Pascal program.

type
  IMyInterface = interface
  end;

  TMyClass = class(TInterfacedObject, IMyInterface)
  end;

var
  MyInstance: TMyClass;

procedure DoSomething(MyParameter: IMyInterface);
begin
end;

begin
  MyInstance := TMyClass.Create;

  DoSomething(MyInstance);

  MyInstance.Free;
end.

The program crashes during the access to the destructor with a SIGSEGV when started from within the IDE (compiled with debug information). Why? It works when I use TInterfacedObject, TObject, or TMyClass as parameter type. It even works when I use the const keyword for said parameter. Can anyone explain this behavior? With a quick sideways glance to Java I would expect this to work.

Compiled with FreePascalCompiler 2.6.4, executed under Windows 7.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
nils
  • 1,362
  • 1
  • 8
  • 15

3 Answers3

3

I cannot speak for FPC, but with Delphi it is a bad idea to mix interfaces and objects. In this case you have two solutions:

  1. declare MyInstance as IMyInterface and remove the call to Free.
  2. inherit TMyClass from TInterfacedPersistent.

To clarify what is actually happening: Creating the TMyClass instance and assigning it to MyInstance will keep the reference count to 0. When you pass it to DoSomething a cast to IMyInterface takes place and the reference counter increases. When DoSomething ends the reference counter decreases to 0 and the instance is freed. The following call to Free will free an already freed instance.

Uwe Raabe
  • 45,288
  • 3
  • 82
  • 130
  • That explains quite a lot, thank you. I had no idea that the interfaces in Delphi work that way. I guess I will probably do without them. However, can you explain what happened, when I used the const keyword? Does this avoid this implicit cast or the reference counting somehow? – nils Aug 26 '14 at 20:48
  • 1
    The const keyword prohibits the reference counting for the interface parameter. Although that might work in this case it is not recommended to rely on it. – Uwe Raabe Aug 26 '14 at 22:44
2

DoSomething expect a IMyInterface

when you pass MyInstance , it's make a counter control, so when the method DoSomething finish, MyInstance has a counter decrement.

the TMyClass is a TInterfacedObject, so when the counter = 0, then Object will be freed, so you don't need to call MyInstance.Free;

you can do:

DoSomething(TMyClass.Create);
Passella
  • 640
  • 1
  • 8
  • 23
0

Your Object uses Reference Counting, to free it you must decrement the reference count. An alternative is to use what's called CORBA interfaces.

In FPC object pascal mode a CORBA interface is a pure interface which does not derivates from IUnknown (in opposite to COM interfaces). If you add the compiler directive:

{$INTERFACES CORBA}

then you'll be able to use the .Free method, just like with any other TObject instance. Note that the name can be confusing since CORBA is a full cross-language specification (IDL), but here corba just means "not COM".

online reference: http://www.freepascal.org/docs-html/ref/refse44.html#x98-1080007.6

Abstract type
  • 1,901
  • 2
  • 15
  • 26