TMyClass = class(TObject)
private
FMyObject: TObject;
function GetMyObject: TObject;
public
property MyObject: TObject read GetMy开发者_StackOverflowObject write FMyObject;
end;
function TMyClass.GetMyObject: TObject;
begin
if FMyObject = nil then
FMyObject := TObject.Create;
Result := FMyObject;
end;
Sometimes, "MyObject" is not created internally but externally created and assigned to the parameter. If this object is created externally, I can not free it in this context.
Should I create a TList and Add in all objects that were created internally and destroy everything on the destructor?
How can I control the lifetime of a parameter if it is created internally or not? What you suggest to do? Is there any pattern to do this?
I'd set a flag in the Property Setter
procedure TMyClass.SetMyObject(AObject: TObject);
begin
if Assigned(MyObject) and FIsMyObject then
FMyObject.Free;
FIsMyObject := False;
FMyObject := AObject;
end;
function TMyClass.GetMyObject: TObject;
begin
if FMyObject = nil then
begin
FMyObject := TObject.Create;
FIsMyObject := True;
end;
Result := FMyObject;
end;
Destructor TMyClass.Destroy;
begin
if FIsMyObject then
FMyObject.Free;
end;
I guess the best would be to redesign your code so that this problem won't arise - this kind of ownership ambiguity is a mess.
Anyway, one option would be to use (reference counted) interfaces. This is problematic in case of circular references.
If the externally created object must not be the only reference then you could still create internal copy of the object, something like
procedure TMyClass.SetMyObject(const Value: TObject);
begin
MyObject.Assign(Value);
end;
You could assign external object to different field than internal and then you don't Free
that field in destructor. Or set a flag in the property setter so that you know not to free the external object...
The two most logical and practical solutions (keep a flag, copy on assignment) are already given, but for completeness sake and since the object field isn't likely to be of the TObject type, here are three other approaches. The practicality of these depends on the type of the object field, whether you really don't want an extra boolean flag and whether you dislike to add some intelligent behavior to this construction.
(Warning: this may be a little farfetched.)
Test if the object field is of your private object type:
property MyObject: TSomeAncestor read GetMyObject write SetMyObject; end; implementation type TMyObject = class(TSomeAncestor) ... end; destructor TMyClass.Destroy; begin if FMyObject is TMyObject then FMyObject.Free;
Test on the ownership of the object field:
property MyObject: TOwnedObject read GetMyObject write SetMyObject; end; implementation destructor TMyClass.Destroy; begin if FMyObject.Owner = Self then FMyObject.Free;
This construction is especially useful if the external object should anyway be freed by this class: just set its Owner to this class instance. The decision depends no longer on the internal or external creation of the object.
If the object field descends from TComponent, then you do not have to free at all.
精彩评论