Q: How do I determine if a variable, which should have been assigned with a TMyOtherObj.create(), but wasn't?
Q: How do I determine if a variable, which should have been assigned with a TMyOtherObj.create(), but wasn't?
It appears that Assigned() does not do this; as evaluating a
Here's a quick sample code (not intended to be compile-able), just an attempt to document the question.
procedure TMyObj.AFunc(var AReturn : TMyOtherObj)
begin
if (Assigned(AReturn)) then
AReturn.DoSomeThing();
end;
var
AObj : TMyObj;
AReturn : TMyOtherObj;
begin
AObj := TMyObj.create();
try
//FORGOT THIS LINE
//AReturn := TMyOtherObj.create();
AObj.AFunc(AReturn);
finally
AObj.Free();
end.
It appears that Assigned() does not do this; as evaluating a
Here's a quick sample code (not intended to be compile-able), just an attempt to document the question.
procedure TMyObj.AFunc(var AReturn : TMyOtherObj)
begin
if (Assigned(AReturn)) then
AReturn.DoSomeThing();
end;
var
AObj : TMyObj;
AReturn : TMyOtherObj;
begin
AObj := TMyObj.create();
try
//FORGOT THIS LINE
//AReturn := TMyOtherObj.create();
AObj.AFunc(AReturn);
finally
AObj.Free();
end.
As you already have figured out, Delphi does not initialize local variables. There are some exceptions to this rule though:
ReplyDeleteStrings, dynamic arrays and interfaces.
Also, global variables and fields (of objects) are initialized to zero (nil, false or whatever zero means for the variable type).
A for FreeAndNil: You might be surprised that some people argue that using it is considered bad practice. (I am not one of them.).
Yeah, it was surprising that I can make an TObject with properties for Events and they are always NIL'd out and a simple Assigned(TObject.AEvent) allows me to call it. Was bummed out that this is only for certain cases.
ReplyDeleteTMyOtherObj = class(TObject)
end;
MyEvent = procedure(AObj : TMyObj) of object;
TMyObj = class(TObject)
private
FEvent : TMyEvent
public
property Event : TNotifyEvent
read FEvent
write FEvent
procedure TriggerEvent(AObj : TMyOtherObj);
end;
..
procedure TMyObj.TriggerEvent();
var
AMyOtherObj : TMyOtherObj;
begin
AMyOtherObj := NIL; // * new template to NIL first
if (assigned(self.FEvent)) then
begin
// oops, forgot ... AMyOtherObj := TMyOtherObj.create();
try
self.FEvent(AMyOtherObj);
finally
FreeAndNil(AMyOtherObj);
end;
end;
end;
...
In the end, setting the variable to NIL each time is something to remember. Just like remembering to assigned it with a TObject.create(). So it makes it easier to spot, but not a terrific method.
In regards to the FreeAndNil(), I'm not sure where I land on this... personally, anything that helps me recover from a mistake is nice. I understand that there's no need to perform a FreeAndNil(), if you don't forget to correctly deal with a variable after it was *.Free()'d. But then again, I don't make any errors in my code that I intend. My goal this past couple weeks is to find all memory related issues. Everything I've found so far was a mistake, something I forgot to do first. Admittedly, several of them have been the result of using a "var" parameter to return an object and not strictly adhering to a "factory"; mainly because I thought Assigned() would help me determine if the object was created before calling. Big mistake.
TObject zeroes its memory when beign crated. It is not about events only, it is abotu all the inner variables.
ReplyDeleteThat is one of the reasons creating classes instances is slow and expensive, comparing to stack-based local variables as records or old-style objects