Delphi: How to free object created dynamically as a parameter of method - delphi

I have method with a parameter as object (sniped code below):
TMyObject=class(TObject)
constructor Create();
destructor Destroy();override;
end;
implementation
function doSomething(x:TMyObject):integer;
begin
//code
end;
procedure test();
var
w:integer;
begin
w:=doSomething(TMyObject.Create);
//here: how to free the created object in line above?
end;
How destroy object created inside of called method doSomething outside of this method?

In order to free the object instance, you need to have a reference to it on which you can call Free().
Since you are creating the object instance in-place as a parameter, the only reference you will have is the one inside of the doSomething() parameter.
You either have to Free it inside of doSomething() (which is practice I would not advise doing):
function doSomething(x: TMyObject): Integer;
begin
try
//code
finally
x.Free;
end;
end;
Or, you need to create an additional variable in test(), pass it to doSomething(), and then Free it after doSomething() returns:
procedure test();
var
w: Integer;
o: TMyObject
begin
o := TMyObject.Create;
try
w := doSomething(o);
finally
o.Free;
end;
end;
While one may think that using a reference counted object would allow you to create the object in-place and let reference counting free the object, this kind of construction may not work because of the following compiler issue:
The compiler should keep a hidden reference when passing freshly created object instances directly as const interface parameters
This is confirmed by a former Embarcadero compiler engineer, Barry Kelly, in a StackOverflow answer:
Should the compiler hint/warn when passing object instances directly as const interface parameters?

Related

reference to procedure and self

When I'm in a TForm (say, MyForm) that has a procedure oneProc (procedure TMyForm.oneProc), if I do inside any procedure of MyForm something like TThread.Queue(nil, oneProc);, how does it end up that when oneProc() is fired that Self is well initialized to MyForm?
Can you explain why this works?
procedure TMyForm.Button1Click(Sender: TObject);
begin
ProcA(ProcB);
end;
procedure TMyForm.ProcA(const Aproc: Tproc);
begin
Aproc;
end;
procedure TMyForm.ProcB;
begin
showmessage(self.className); // << this show TTMyForm (how?)
end;
First off, TThread.Queue() is overloaded to accept both TThreadMethod (non-anonymous) and TThreadProcedure (anonymous) parameters. Your text description is for code that would call the non-anonymous version. Your code example, on the other hand, is doing something a little different than what your described TThread.Queue() code would be doing. But in any case, to answer your question -
A non-anonymous method pointer actually carries 2 values within it - one is the address of the method, and one is the value passed to the method's Self parameter (a method pointer is represented by the TMethod record).
TProc is a reference to an anonymous method, and a non-anonymous method pointer can be assigned to an anonymous method reference. The documentation even says so, in the section on "Using Anonymous Methods":
Method references can also be assigned to methods as well as anonymous methods. For example:
type
TMethRef = reference to procedure(x: Integer);
TMyClass = class
procedure Method(x: Integer);
end;
var
m: TMethRef;
i: TMyClass;
begin
// ...
m := i.Method; //assigning to method reference
end;
However, the converse is not true: you cannot assign an anonymous method to a regular method pointer. Method references are managed types, but method pointers are unmanaged types. Thus, for type-safety reasons, assigning method references to method pointers is not supported. For instance, events are method pointer-valued properties, so you cannot use an anonymous method for an event. See the section on variable binding for more information on this restriction.
Internally, an anonymous method reference is implemented as a compiler-generated reference-counted interface with a single Invoke() method. When you write an anonymous method in code, the compiler generates a hidden class that implements Invoke() with that code. Any variables that the anonymous method captures are stored as members of that class.
When assigning a non-anonymous method pointer to an anonymous method reference, the compiler generates a class that captures that method pointer and then calls it inside of the generated Invoke().
So, given the code you have shown, the compiler would translate it into something roughly like the following (I'm leaving out implementation details that are not relevant):
type
//TProc = reference to procedure;
TProc_Intf = interface
procedure Invoke;
end;
TProc_Generated = class(TInterfacedObject, TProc_Intf)
FProc: procedure of object; // type of TMyForm.ProcB()
procedure Invoke;
end;
procedure TProc_Generated.Invoke;
begin
FProc; // <-- calls FProc.Code with FProc.Data as Self!
end;
procedure TMyForm.Button1Click(Sender: TObject);
var
Intf: TProc_Intf;
begin
//ProcA(ProcB);
Intf := TProc_Generated.Create;
//TProc_Generated(Intf).FProc := #ProcB;
TMethod(TProc_Generated(Intf).FProc).Code := Addr(ProcB);
TMethod(TProc_Generated(Intf).FProc).Data := Self; // <-- Self stored here!
ProcA(Intf);
end;
procedure TMyForm.ProcA(const Aproc: {TProc}TProc_Intf);
begin
//Aproc;
Aproc.Invoke;
end;
procedure TMyForm.ProcB;
begin
ShowMessage(Self.ClassName); // <-- Self valid here!
end;
That is how the Self gets from Button1Click() to ProcB() through ProcA().

Can I make a constructor that deserializes a string version of my object?

I'm serializing and deserializing an object (TComponent descendant) using the example in the ComponentToString section in the Delphi help file. This is so I can store the object in a VARCHAR field in the database.
When I need to instantiate a new instance of my class from a string stored in the database, can I do that using a constructor of the form CreateFromString(AOwner: TComponent; AData: String)? Or do I have to use a non-class method that returns an instance of my component class?
If I can use the constructor version, how to I "map" the return value of ReadComponent to the "self" that is being created by the constructor?
Here's the deserialization example from the help file:
function StringToComponentProc(Value: string): TComponent;
var
StrStream:TStringStream;
BinStream: TMemoryStream;
begin
StrStream := TStringStream.Create(Value);
try
BinStream := TMemoryStream.Create;
try
ObjectTextToBinary(StrStream, BinStream);
BinStream.Seek(0, soFromBeginning);
Result:= BinStream.ReadComponent(nil);
finally
BinStream.Free;
end;
finally
StrStream.Free;
end;
end;
In general, yes, you can make a constructor deserialize a string and use that information to initialize the new instance. A trivial example of that would be a class with a single Integer field. Pass a string to the constructor and have the constructor call StrToInt and initialize the field with the result.
But if the only function you have for deserialization is one that also creates the instance, then you cannot use that from the constructor because then you'll end up with two instances when you only wanted one. There's no way for a constructor to say, "Never mind; don't construct an instance after all. I already got one somewhere else."
However, that's not the situation you're in. As you should know, TStream.ReadComponent allows you to create the instance yourself. It only instantiates the class if you haven't already given it an instance to use. You should be able to write your constructor like this:
constructor TLarryComponent.CreateFromString(const AData: string);
var
StrStream, BinStream: TStream;
begin
Create(nil);
StrStream := TStringStream.Create(AData);
try
BinStream := TMemoryStream.Create;
try
ObjectTextToBinary(StrStream, BinStream);
BinStream.Position := 0;
BinStream.ReadComponent(Self);
finally
BinStream.Free;
end;
finally
StrStream.Free;
end;
end;
There we're passing the current object, designated by Self, to ReadComponent. The stream will ignore the class name stored in the stream and assume that the current object is of the correct class.
You can do this by a class (static) method, but not via a constructor.
Delphis' constructors are called by compiler intrinsic on the just-created instance, which is already partially initialized (it's of the desired class and instance/field storage is zeroed-out).
If you see the source of TStream.ReadComponent, you'll find that the components' real class is read from the source stream at first, then an empty instance is constructed and filled by RTTI from the stream and returned as the result. Which means:
To use TStream.ReadComponent, you'll need to register your class to Delphis' streaming system via RegisterClass.
Use a static class function instead of a constructor:
type
TYourClass = class(TComponent)
public
class function CreateFromString(AOwner: TComponent; AData: String): TYourClass; static;
end;
implementation
class function TYourClass.CreateFromString(AOwner: TComponent; AData: String): TYourClass;
begin
Result := (StringToComponentProc(AData) as TYourClass);
if AOwner <> nil then
AOwner.InsertComponent(Result);
end;
The AOwner part could be a problem though, since TStream.ReadComponent has no parameter for the owner.
There is another so question about that problem:
How can I specify the Owner of component read from a Delphi TStream?
Edit: I've updated the code sample to include the owner, too.
Note that inserting into the component list of the owner requires a unique or empty Name for the component that is being inserted.

How to pass a method as callback to a Windows API call?

I'd like to pass a method of a class as callback to a WinAPI function. Is this possible and if yes, how?
Example case for setting a timer:
TMyClass = class
public
procedure TimerProc(Wnd:HWND; uMsg:DWORD; idEvent:PDWORD; dwTime:DWORD);
procedure DoIt;
end;
[...]
procedure TMyClass.DoIt;
begin
SetTimer(0, 0, 8, #TimerProc); // <-???- that's what I want to do (last param)
end;
Thanks for your help!
Edit: The goal is to specify a method of this class as callback. No procedure outside the class.
Edit2: I appreciate all your help but as long as the method has no "TMyClass." in front of its name it is not what I am searching for. I used to do it this way but wondered if could stay fully in the object oriented world. Pointer magic welcome.
Madshi has a MethodToProcedure procedure. It's in the "madTools.pas" which is in the "madBasic" package. If you use it, you should change the calling convention for "TimerProc" to stdcall and DoIt procedure would become,
TMyClass = class
private
Timer: UINT;
SetTimerProc: Pointer;
[...]
procedure TMyClass.DoIt;
begin
SetTimerProc := MethodToProcedure(Self, #TMyClass.TimerProc);
Timer := SetTimer(0, 0, 8, SetTimerProc);
end;
// After "KillTimer(0, Timer)" is called call:
// VirtualFree(SetTimerProc, 0, MEM_RELEASE);
I've never tried but I think one could also try to duplicate the code in the "classses.MakeObjectInstance" for passing other procedure types than TWndMethod.
Which version of Delphi are you using?
In recent ones you can use static class methods for this:
TMyClass = class
public
class procedure TimerProc(Wnd:HWND; uMsg:DWORD; idEvent:PDWORD; dwTime:DWORD); stdcall; static;
procedure DoIt;
end;
[...]
procedure TMyClass.DoIt;
begin
SetTimer(0, 0, 8, #TimerProc);
end;
The TimerProc procedure should be a standard procedure, not a method pointer.
A method pointer is really a pair of
pointers; the first stores the address
of a method, and the second stores a
reference to the object the method
belongs to
Edit
This might be as much OOP as you are going to get it. All the nasty stuff is hidden from anyone using your TMyClass.
unit Unit2;
interface
type
TMyClass = class
private
FTimerID: Integer;
FPrivateValue: Boolean;
public
constructor Create;
destructor Destroy; override;
procedure DoIt;
end;
implementation
uses
Windows, Classes;
var
ClassList: TList;
constructor TMyClass.Create;
begin
inherited Create;
ClassList.Add(Self);
end;
destructor TMyClass.Destroy;
var
I: Integer;
begin
I := ClassList.IndexOf(Self);
if I <> -1 then
ClassList.Delete(I);
inherited;
end;
procedure TimerProc(Wnd:HWND; uMsg:DWORD; idEvent:PDWORD; dwTime:DWORD); stdcall;
var
I: Integer;
myClass: TMyClass;
begin
for I := 0 to Pred(ClassList.Count) do
begin
myClass := TMyClass(ClassList[I]);
if myClass.FTimerID = Integer(idEvent) then
myClass.FPrivateValue := True;
end;
end;
procedure TMyClass.DoIt;
begin
FTimerID := SetTimer(0, 0, 8, #TimerProc); // <-???- that's what I want to do (last param)
end;
initialization
ClassList := TList.Create;
finalization
ClassList.Free;
end.
Edit: (as mentioned by glob)
Don't forget to add the stdcall calling convention.
Response to your second edit:
If you want a reply that includes a pointer to a TMyClass instance, you may be out of luck. Fundamentally, the procedure Windows will call has a certain signature and is not an object method. You cannot directly work around that, not even with __closure or procedure of object magic, except as described below and in other answers. Why?
Windows has no knowledge of it being an object method, and wants to call a procedure with a specific signature.
The pointer is no longer a simple pointer - it has two halves, the object instance and the method. It needs to save the Self, as well as the method.
By the way, I don't understand what is wrong with a short dip outside the object-oriented world. Non-OO code is not necessarily dirty if used well.
Original, pre-your-edit answer:
It's not possible exactly as you are trying to do it. The method that SetTimer wants must exactly follow the TIMERPROC signature - see the MSDN documentation. This is a simple, non-object procedure.
However, the method TMyClass.DoIt is an object method. It actually has two parts: the object on which it is called, and the method itself. In Delphi, this is a "procedure of object" or a "closure" (read about procedural types here). So, the signatures are not compatible, and you cannot store the object instance, which you need in order to call an object method. (There are also calling convention problems - standard Delphi methods are implemented using the fastcall convention, whereas TIMERPROC specifies CALLBACK which, from memory, is a macro that expands to stdcall. Read more about calling conventions and especially fastcall.)
So, what do you do? You need to map your non-object-oriented callback into object-oriented code.
There are several ways, and the simplest is this:
If you only have one timer ever, then you know that when your timer callback is called it is that specific timer that fired. Save a method pointer in a variable that is of type procedure of object with the appropriate signature. See the Embarcadero documentation link above for more details. It will probably look like:
type TMyObjectProc = procedure of object;
var pfMyProc : TMyObjectProc;
Then, initialise pfMyProc to nil. In TMyClass.DoIt, set pfMyProc to #DoIt - that is, it is now pointing at the DoIt procedure in the context of that specific TMyClass instantiation. Your callback can then call that method.
(If you're interested, class variables that are of a procedural type like this are how event handlers are stored internally. The OnFoo properties of a VCL object are pointers to object procedures.)
Unfortunately this procedural architecture is not object-oriented, but it's how it has to be done.
Here's what some full code might look like (I'm not at a compiler, so it may not work as written, but it should be close):
type TMyObjectProc = procedure of object;
var pfMyProc : TMyObjectProc;
initialization
pfMyProc = nil;
procedure MyTimerCallback(hWnd : HWND; uMsg : DWORD; idEvent : PDWORD; dwTime : DWORD); stdcall;
begin
if Assigned(pfMyProc) then begin
pfMyProc(); // Calls DoIt, for the object that set the timer
pfMyProc = nil;
end;
end;
procedure TMyClass.MyOOCallback;
begin
// Handle your callback here
end;
procedure TMyClass.DoIt;
begin
pfMyProc = #MyOOCallback;
SetTimer(0, 0, 8, # MyTimerCallback);
end;
Another way would be to take advantage of the fact your timer has a unique ID. Save a mapping between the timer ID and the the object. In the callback, convert from the ID to the pointer, and call the object's method.
Edit: I've noticed a comment to another answer suggesting using the address of your object as the timer ID. This will work, but is a potentially dangerous hack if you end up having two objects at the same address at different times, and you don't call KillTimer. I've used that method but don't personally like it - I think the extra bookkeeping of keeping a (timer ID, object pointer) map is better. It really comes down to personal style, though.
I've used MakeObjectInstance a few times to do the same.
Here's an article on the subject:
How to use a VCL class member-function as a Win32 callback
TMyClass = class
public
procedure DoIt;
procedure DoOnTimerViaMethod;
end;
var MyReceiverObject: TMyClass;
[...]
procedure TimerProc(Wnd:HWND; uMsg:DWORD; idEvent:PDWORD; dwTime:DWORD); stdcall:
begin
if Assigned(MyReceiverObject) then
MyReceiverObject.DoOnTimerViaMethod;
end;
procedure TMyClass.DoIt;
begin
MyReceiverObject := Self;
SetTimer(0, 0, 8, #TimerProc); // <-???- that's what I want to do (last param)
end;
Not perfect. Watch for the threads, variable overwriting etc. But it does the job.

How to create an instance of object with RTTI in Delphi 2010?

As we all known, when we call a constructor of a class like this:
instance := TSomeClass.Create;
The Delphi compiler actually do the following things:
Call the static NewInstance method
to allocate memory and initialize
the memory layout.
Call the constructor method to
perform the initialization of the class
Call the AfterConstruction method
It's simple and easy to understand. but I'm not very sure how the compiler handle exceptions in the second and the third step.
It seems there are no explicit way to create an instance using a RTTI constructor method in D2010. so I wrote a simple function in the Spring Framework for Delphi to reproduce the process of the creation.
class function TActivator.CreateInstance(instanceType: TRttiInstanceType;
constructorMethod: TRttiMethod; const arguments: array of TValue): TObject;
var
classType: TClass;
begin
TArgument.CheckNotNull(instanceType, 'instanceType');
TArgument.CheckNotNull(constructorMethod, 'constructorMethod');
classType := instanceType.MetaclassType;
Result := classType.NewInstance;
try
constructorMethod.Invoke(Result, arguments);
except
on Exception do
begin
if Result is TInterfacedObject then
begin
Dec(TInterfacedObjectHack(Result).FRefCount);
end;
Result.Free;
raise;
end;
end;
try
Result.AfterConstruction;
except
on Exception do
begin
Result.Free;
raise;
end;
end;
end;
I feel it maybe not 100% right. so please show me the way. Thanks!
Invoking the constructor and passing the class as the Self argument (as opposed to an instance) will correctly construct the class. The process of constructing includes the NewInstance, AfterConstruction etc. that you are manually doing here: it's not necessary.
This ought to be sufficient:
Result := constructorMethod.Invoke(instanceType.MetaclassType, arguments);
An oddity of Delphi is how it permits constructors to be called on instances as well as classes. This feature is used as a kind of "placement new" (in C++ terminology) for form construction, so that the global form variable (e.g. Form1 by default for the first form) is assigned at the time that the OnCreate constructor gets invoked. Thus, your code doesn't raise an exception. But it is more normal to pass the class rather than the instance as the Self argument.

How to automatically free classes/objects?

What techniques exist to automatically free objects in delphi applications?
Use interfaces instead of objects. They are reference counted and freed automatically when the reference count reaches 0.
I have written a function GC(obj: TObject) (for Garbage Collect) which takes an object and frees it when the execution leaves the current method. It's kind of like a one-line shorthand function for a Try Finally Free block.
Instead of:
procedure Test;
var AQuery: TQuery;
begin
AQuery := TQuery.Create(nil);
try
...
finally
FreeAndNil(AQuery);
end;
end;
I just have:
procedure Test;
var AQuery: TQuery;
begin
AQuery := TQuery.Create(nil);
GC(AQuery);
...
end;
The GC function simply returns an object in the form of an interface.
function GC(obj: TObject): IGarbo;
begin
Result := TGarbo.Create(obj);
end;
Because the TGarbo class descends from TInterfacedObject, when the TGarbo object goes out of scope it will automatically get freed. In the destructor of the TGarbo object, it also frees the object you passed to it in it's constructor (the object you passed in the GC function).
type
IGarbo = interface
['{A6E17957-C233-4433-BCBD-3B53C0C2C596}']
function Obj: TObject;
end;
TGarbo = class(TInterfacedObject, IGarbo)
private
FObj: TObject;
public
constructor Create(AObjectToGC: TObject);
destructor Destroy; override;
function Obj: TObject;
end;
{ TGarbo }
constructor TGarbo.Create(AObjectToGC: TObject);
begin
inherited Create;
FObj := AObjectToGC;
end;
destructor TGarbo.Destroy;
begin
if Assigned(FObj) then
FreeAndNil(FObj);
inherited;
end;
function TGarbo.Obj: TObject;
begin
Result := FObj;
end;
Being stuck in the world of Delphi 7 with no sight of upgrading to a version of Delphi with built-in garbage collection in the near future, I'm addicted to using this short-hand method of easily freeing local temporary objects! :)
Along the lines of interfaces, you can try the Guard function in the JclSysUtils unit, part of the free Jedi Code Library. It allows you to associate an object with a separate interface reference, so when that interface reference is destroyed, the object is destroyed along with it. This can be useful when you don't have the option of modifying the classes you're using to make them support interfaces of their own.
var
G: ISafeGuard;
foo: TStrings;
begin
// Guard returns TObject, so a type-cast is necessary
foo := Guard(TStringList.Create, G) as TStrings;
// Use the object as normal
foo.Add('bar');
end; // foo gets freed automatically as G goes out of scope
There are overloads for objects and GetMem-allocated pointers. There is also IMultiSafeGuard, which can ensure that multiple objects get freed.
If you have a factory function, you might be creating an object, setting some of its properties, and then returning it. If an exception occurs while setting the properties, you'll want to make sure you free the object since you can't return it. One way to do that is like this:
function Slurp(const source: TFileName): TStrings;
begin
Result := TStringList.Create;
try
Result.LoadFromFile(source);
except
Result.Free;
raise;
end;
end;
With Guard, it would become this:
function Slurp(const source: TFileName): TStrings;
var
G: ISafeGuard;
begin
Result := Guard(TStringList.Create, G) as TStrings;
Result.LoadFromFile(source);
G.ReleaseItem;
end;
The ReleaseItem method revokes the ISafeGuard's ownership of the object. If an exception occurs before that happens, then as the stack unwinds and the interface is released, the guard will free the object.
I have to say, I don't like "hiding" the Free of an object. Far better to have the traditional code:
MyObject := TObject.Create;
try
// do stuff
finally
FreeAndNil(MyObject);
end;
No way it can go wrong, works as expected, and people recognise the pattern.
Use the object ownership of components that the VCL provides. As long as you create objects with a non-nil owner you don't need to free them explicitely. See also my answer to this question.
Here is the API for Boehm Garbage Collector DLL for Delphi. The Delphi API is written by Barry Kelly, who works for CodeGear writing the compiler now.
Smart Pointers work really well if you have Delphi 2009.
If you use Delphi for .Net / Delphi Prism you get Garbage Collection which takes care of all the freeing.

Resources