Счетчик HotLog

На главнуюЧто я делаю...Программы автора и не только...Творчество
Статьи автораКнига отзывов и предложенийОбо мне, любимомФотоальбом

 
 

TObjectList: чем отличаются методы Delete и Remove

Очень удобный класс для работы со списком объектов. Вот только не до конца понятный. Справка Delphi вводит в заблуждение, возникают вопросы. Выдержка из Help'а:

Remove method (TObjectList)

Removes a specified object from the list and (if OwnsObjects is true) frees the object.

Delphi syntax:
function Remove(AObject: TObject): Integer;

C++ syntax:
HIDESBASE int __fastcall Remove(System::TObject* AObject);

Description
Call Remove to delete a specific object from the list when its index is unknown. The value returned is the index of the object in the Items array before it was removed. If the specified object is not found on the list, Remove returns –1. If OwnsObjects is true, Remove frees the object in addition to removing it from the list.

After an object is deleted, all the objects that follow it are moved up in index position and Count is decremented. If an object appears more than once on the list, Remove deletes only the first appearance. Hence, if OwnsObjects is true, removing an object that appears more than once results in empty object references later in the list.

To use an index position (rather than an object reference) to specify the object to be removed, call Delete.

To remove an object from the list without freeing it, call Extract.

 

Delete method (TList)

Removes the item at the position given by the Index parameter.

Delphi syntax:
procedure Delete(Index: Integer);

C++ syntax:
void __fastcall Delete(int Index);

Description
Call Delete to remove the item at a specific position from the list. The index is zero-based, so the first item has an Index value of 0, the second item has an Index value of 1, and so on. Calling Delete moves up all items in the Items array that follow the deleted item, and reduces the Count.

To remove the reference to an item without deleting the entry from the Items array and changing the Count, set the Items property for Index to nil (Delphi) or NULL (C++).

Note: Delete does not free any memory associated with the item. To free the memory that was used to store a deleted item, set the Capacity property.

Обратите внимание, что описание метода Delete дается для предка класса TObjectList - TList, что добавляет путаницы. Еще примем во внимание примечание (Note) в описании метода и запутаемся окончательно.

Я обратился к этой теме по простой причине: у меня были проблемы с этими двумя методами, я не знал, какой из них использовать в определенных случаях.

Лучший способ разобраться в работе - обратиться к исходникам. Так и поступим.

Итак, что мы видим в исходниках метода Remove:

{ TObjectList }
function TObjectList.Remove(AObject: TObject): Integer;
begin
  Result := inherited Remove(AObject);
end;

То есть вызывается одноименный метод предка TList:

{ TList }
function TObjectList.Remove(AObject: TObject): Integer;
begin
  Result := IndexOf(Item);
  if Result >= 0 then
    Delete(Result);
end;

Здесь, как мы видим, вызывается метод Delete, из чего можно заключить, что никакой разницы между методами Remove и Delete (кроме типа аргумента) нет. Но мы не будем останавливаться на этом, а пойдем дальше и посмотрим устройство метода TList.Delete:

{ TList }
procedure TList.Delete(Index: Integer);
var
  Temp: Pointer;
begin
  if (Index < 0) or (Index >= FCount) then
    Error(@SListIndexError, Index);
  Temp := Items[Index];
  Dec(FCount);
  if Index < FCount then
    System.Move(FList^[Index + 1], FList^[Index],
      (FCount - Index) * SizeOf(Pointer));
  if Temp <> nil then
    Notify(Temp, lnDeleted);
end;

Тут вызывается метод Notify, в котором, как мы сейчас убедимся, кроется вся хитрость класса TObjectList:

{ TList }
procedure TList.Notify(Ptr: Pointer; Action: TListNotification);
begin
end;

{ TObjectList }
procedure TObjectList.Notify(Ptr: Pointer; Action: TListNotification);
begin
  if OwnsObjects then
    if Action = lnDeleted then
      TObject(Ptr).Free;
  inherited Notify(Ptr, Action);
end;

Так, мы убедились, что если свойство OwnsObjects объекта класса TObjectList установлено в True, то оба метода: и Delete, и Remove приводят к освобождению объекта, удаляемого из списка. Если OwnsObject = False, ни один из них не освобождает объект. По крайней мере я пришел к этому выводу именно так, через изучение исходников.

Для удаления объекта из списка без его освобождения необходимо использовать метод Extract.

Позже я нашел в справке подтверждение своих мыслей:

TObjectList

TObjectList maintains a list of (owned) objects.

Unit
Contnrs

Description
Use TObjectList to store and maintain a list of objects. TObjectList provides properties and methods to add, delete, rearrange, locate, access, and sort objects. If the OwnsObjects property is set to true (the default), TObjectList controls the memory of its objects, freeing an object when its index is reassigned; when it is removed from the list with the Delete, Remove, or Clear method; or when the TObjectList instance is itself destroyed.

 Внимательнее читать нужно, не будут возникать лишние вопросы :)

 
 

17.04.2007

 
     
Hosted by uCoz