Question

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.

Was it helpful?

Solution

Why not just set OwnsObjects to false, do your removal, then set it to true again?

OTHER TIPS

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);

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.

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top