I have a TObjectList with OwnsObjects = true. It contains quite a few objects. Now I want to remove the object at index Idx from that list, without freeing it.
Is the Extract method the only option?
ExtractedObject := TheList.Extract(TheList[Idx]);
All other methods seem to free the object. I am looking for something a little bit more efficient, that does not do a linear search every time, since I already know the index of the object. Something like an overloaded ...
ExtractedObject := TheList.Extract(Idx);
... which does not exist.
-
I don't use Delphi/C++Builder some time ago, but as far as I can renmember thats the only way. My suggestion is to use a TList instead, and manually delete the objects when required.
-
Why not just set OwnsObjects to false, do your removal, then set it to true again?
Thomas Mueller : too easy ;-) Thanks -
If you look at the code for delete, it's the notify method which causes the freeing to happen.
This should work :
TMyObjectList = Class(TObjectList) private fNotify: Boolean; { Private declarations } procedure EnableNotification; procedure DisableNotification; protected procedure Notify(Ptr: Pointer; Action: TListNotification); override; public constructor Create(AOwnsObjects: Boolean);overload; constructor Create; overload; function Extract(const idx : Integer) : TObject; end; constructor TMyObjectList.Create(AOwnsObjects: Boolean); begin inherited Create(AOwnsObjects); fNotify := True; end; constructor TMyObjectList.Create; begin inherited Create; fNotify := True; end; procedure TMyObjectList.DisableNotification; begin fnotify := False; end; procedure TMyObjectList.EnableNotification; begin fNotify := True; end; function TMyObjectList.Extract(const idx: Integer) : TObject; begin Result := Items[idx]; DisableNotification; try Delete(idx); finally EnableNotification; end; end; procedure TMyObjectList.Notify(Ptr: Pointer; Action: TListNotification); begin if fNotify then inherited; end; -
This is where class helpers can be usefull
TObjectListHelper = class helper for TObjectList function ExtractByIndex(const AIndex: Integer): TObject; end; function TObjectListHelper.ExtractByIndex(const AIndex: Integer): TObject; begin Result := Items[AIndex]; if Result<>nil then Extract(Result); end;You can now use:
MyObjList.ExtractByIndex(MyIndex);Thomas Mueller : Unfortunately this will still do a linear search in the original extract function, even though I already passed the object's index to the new extract function. But I guess combining this with OwnsObjects=False/True should do the trick. -
The proposed helperclass (by Gamecat) will result in the same lookup that Thomas would like to get rid of.
If you take a look at the source, you can see what Extract() really does, and then use the same approach.
I will suggest something like tis:
obj := list[idx]; list.list^[idx] := nil; //<- changed from list[idx] := nil; list.delete(idx);This will give you the object, as Extract() does, and then delete it from the list, without any lookups. Now you can put this in a method some where, a helperclass or subclass or wher ever you like.
Thomas Mueller : Unfortunately this doesn't work either since Assigning NIL to an item automatically frees it.Vegar : Oops. I completly overlooked that one, but TList gives you direct access to the linkedlist, through the public property List: PPoinerList. Change list[idx] := nil to list.List^[i] := nil; and the solution should be sound again. -
Anything wrong with:
ExtractedObject := TExtractedObject.Create;
ExtractedObject.Assign(Thelist[Idx]);
TheList.Delete(idx);There is time needed for the create and assign but not for the search of the list. Efficiency depends on the size of the object -v- the size of the list.
Oliver Giesen : that approach requires the object to descend from TPersistent and to properly implement the Assign method
0 comments:
Post a Comment