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. |
Внимательнее читать нужно, не будут возникать лишние вопросы :) |