关于TList的Notify,还望高手指点(100分)

  • 主题发起人 主题发起人 wind_2005
  • 开始时间 开始时间
W

wind_2005

Unregistered / Unconfirmed
GUEST, unregistred user!
我在看《Delphi算法与数据结构》(Julian Backnall)一书时,其中作者提到(大意):Delphi5以后,TList及其子类的Clear中使用了Notify方法,使得Delphi5以后的TList运行过慢。。。。
我有其他书中也见到了类似的说法。

《Delphi算法与数据结构》(Julian Backnall)一书中,作者给出了他的算法:
procedure TtdObjectList.Clear;
var
i : integer;
begin
{if we own the items present, free them before clearing the list}
if DataOwner then
for i := 0 to pred(FList.Count) do
TObject(FList).Free;
FList.Clear;
end;

而TList的源码如下:
procedure TList.Clear;
begin
SetCount(0); //见下面
SetCapacity(0);
end;

procedure TList.SetCount(NewCount: Integer);
var
I: Integer;
begin
if (NewCount < 0) or (NewCount > MaxListSize) then
Error(@SListCountError, NewCount);
if NewCount > FCapacity then
SetCapacity(NewCount);
if NewCount > FCount then
FillChar(FList^[FCount], (NewCount - FCount) * SizeOf(Pointer), 0)
else
for I := FCount - 1 downto NewCount do
Delete(I); //见下面
FCount := NewCount;
end;

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中实现如下:
procedure TObjectList.Notify(Ptr: Pointer; Action: TListNotification);
begin
if OwnsObjects then
if Action = lnDeleted then
TObject(Ptr).Free;
inherited Notify(Ptr, Action);
end;
===
而我个人感觉(可能是自己水平太次),这和作者的不同之处只是多调了几层涵数,而处理方法是相同的,

那么作者所说的:Notify方法,使得Delphi5以后的TList运行过慢。倒底如何理触,为什么这样说?谢谢!
 
自己顶一下。
 
主要区别:
1、调用路径的增多,导致压/出栈有损耗
2、释放内存的方式变了:
原来的 TList 的 Clear 一次过删除所有开辟的空间(空间是连续的,基本上一个 FreeMem 搞定);
而新的 TList 的 Clear 是通过调用 N 次 Delete(I) 实现的(这样做的目的仅仅是让派生类可以做一些事情,如 TObjectList 的 FreeItem)(尽管最后也是一次 FreeMem)。
实现代码的累赘,这是让 Julian Backnall 不爽的地方。 ;>
 
LSUPER谢谢你。
只是在我的印象中,TList只是一个指针数组,它本身是连续的,但它各元素所指向的对象实例却不是连续的,这些对象实例可能得逐个释放。
所以我感觉,一个 FreeMem 可能没办法搞定。
不知我的理解是否正确,还望多多指点。
不知没有没原来的 TList 的 Clear代码,能不能贴上来看看,谢谢!
 
没人回复了,还是结帖了,哈哈
 
确实是这样。
“TList只是一个指针数组,它本身是连续的,但它各元素所指向的对象实例却不是连续的,这些对象实例可能得逐个释放。”
你这个是针对 TObjectList 说得,对于 TList 就是一个 Pointer 的数组,所以一个 FreeMem 可以销毁所有 Pointer 占用的数组;而恰恰为了上面的功能,为了这唯一一个 TObjectList 修改了父类 TList 的结构,所以 Julian Backnall 非常不同意!
 
后退
顶部