RTTI Free on an object created by Invoke

Asked

Viewed 557 times

0

I’m creating a routine to instantiate a class via RTTI and validate whether this class implements a interface.

I have a test class implemented as follows:

unit teste.classeTeste.uclasseTeste;
interface
uses
  validador;
type
  ClasseTeste = class(TInterfacedObject, IServico)
    private
    public
      function foo: string;
  end;
implementation
{ classe }
function ClasseTeste.foo: string;
begin
  Result := 'Teste foo';
end;
initialization
  ClasseTeste.ClassName;
end.

And I have a Validator class implemented as follows:

unit validador;
interface    
uses
  Rtti;
type
  IServico = interface
  ['{46C26FED-AEDD-456F-B182-DEECB780D264}']
  end;
  Svc = class
    public
      function Validar(pClassName: string): Boolean;
  end;
implementation
uses
  SysUtils;
{ Svc }
function Svc.Validar(pClassName: string): Boolean;
var
  lContext: TRttiContext;
  lType: TRttiInstanceType;
  lObj: TObject;
begin
  Result := False;
  lType := lContext.FindType(pClassName) as TRttiInstanceType;
  if lType = nil then
    raise Exception.Create('Classe solicitada não encontrada no sistema ou ClassNameInválido');
  lObj := lType.GetMethod('Create').Invoke(lType.MetaclassType, []).AsObject;
  try
    if not Supports(lObj, IServico) then
      raise Exception.Create('A classe serviço não implementa a interface IServico!');
  finally
    lObj.Free;
  end;
  Result := True;
end;
end.

The question is: In the Validate method, in the line

`lObj.Free`;

It bursts

"Invalid Pointer Operation".

Theoretically I have a TObject instantiated. It needs to be released at some point. How and when I release it?

Note: I am using Delphi 2010.

  • You passed 'ClasseTeste' for the execution of your trial?

  • Actually, for RTTI to work, I have to pass namespace + class. The call was: if objValidador.Validate('test.classeTeste.uclasseThis.Classeteste') then Showmessage('Validate Class!');

  • Sorry, but I need to learn how to use this editor yet...

  • 1

    I think it’s because it’s derived from interface, and then Delphi itself gets rid of the instance. Test with the ReportMemoryLeaksOnShutdown := True, and do not execute the Free. If when closing the application does not show a message with "Classeteste X1" then what I said is happening.

  • In Delphi 2010, Fastmm does not come embedded. I added and rode. Without giving the Free it does not accuse any "Memoryleak". I created a new variable (lob2), I created the create and did not give the Free, and accused the "Memoryleak". Anyway, I was afraid because lObj := lType.Getmethod('Create'). Invoke(lType.Metaclasstype, []). Asobject; in my view, it would return me a Tobject and not an interface.

  • I really don’t know how to give you a plausible explanation of why by RTTI it is using management via interface since you’re saying you want to create a Classeteste and not an Iservico. Really, if you create a variable that even if you inherit an interface, but you define that the variable is Classeteste, it wasn’t meant to be managed as an interface, and then causes a Memoryleak.

  • Still...in Invoke - Invoke(lType.Metaclasstype, []). Asobject - I’m asking him to return me "Asobject" :D

Show 2 more comments

1 answer

0

the problem is on the line if not Supports(lObj, IServico) then

when the Supports function is called it releases the lObj and as you call the free always

finally
   lObj.Free;
end;

it tries to release again, causing the error, make the test, implement the method

destructor Destroy; override;

in his class Classeteste and you will see that he calls Free twice.

  • I’m sorry, but I couldn’t see it. The Supports function code, in Sysutils, Result := (Instance <> nil) and (Instance.QueryInterface(IID, Intf) = 0);

  • debugging your example here, and implementing Stroy realized this

Browser other questions tagged

You are not signed in. Login or sign up in order to post.