Delphi EListError列表索引超出范围(0)-t格式项

Delphi EListError列表索引超出范围(0)-t格式项,delphi,tlist,Delphi,Tlist,我有一个有趣的bug需要修复。我已经准备好了两个解决方案,但在实现其中一个之前,我想问一下为什么会发生这样的错误。我问这个问题的原因是因为我无法复制这个bug,所以我正在实施一种故障恢复解决方案 我得到的错误出现在TList对象上:“[EListError]列表索引超出范围(0)”。 TList包含一些t表单对象,我们将它们设置为不可见,然后在该操作之后立即将它们添加到TList。现在我们想让它们再次可见并释放,然后将TList置零。当我们想使窗体再次可见时,会发生错误 因此有一个循环,TLis

我有一个有趣的bug需要修复。我已经准备好了两个解决方案,但在实现其中一个之前,我想问一下为什么会发生这样的错误。我问这个问题的原因是因为我无法复制这个bug,所以我正在实施一种故障恢复解决方案

我得到的错误出现在
TList
对象上:“[EListError]列表索引超出范围(0)”。
TList
包含一些
t表单
对象,我们将它们设置为不可见,然后在该操作之后立即将它们添加到
TList
。现在我们想让它们再次可见并释放,然后将
TList
置零。当我们想使窗体再次可见时,会发生错误

因此有一个循环,
TList.Count
有一个值。代码进入循环,出现上述错误。上面的错误不表示特定索引中没有项,但列表计数大于零,这怎么可能

这里唯一不寻常的事情可能是for循环倒计时,以便我们以相反的顺序显示表单

for ii := FormListObject.Count - 1 downto 0 do begin
   // Error happens here
   TForm(FormListObject[ii]).Show;
end;
您认为这是gui线程问题、子项问题还是某种形式的表单被破坏/杀死,并且列表有一个死引用?我仍然认为这个错误意味着索引0中没有TList项,死引用应该触发访问冲突错误,不是吗

我在TList对象上遇到错误:“[EListError]列表索引超出范围(0)”

这很容易理解。您有一个空列表,正在尝试访问索引为零的元素

使用调试器告诉您哪个列表为空。让调试器在异常时中断。然后试着找出为什么代码假设列表不是空的,而事实并非如此

三种可能的原因:

  • 一种内存覆盖,恰好覆盖“可访问”内存中的内容(因此没有AV)。但触发对
    FormListObject
    的无效更改

  • 其他一些东西(如OnShow事件)实际上正在从
    FormListObject
    中删除项。它不必是不同的线程;当然,这也是可能的注意:尽管您询问这是否是GUI线程问题,但我真的怀疑这种情况,因为您必须专门从不同的线程调用GUI代码才能实现这种可能性

  • 重新进入代码导致在循环的中间改变代码> FrimeListObjs<代码>。当您在处理另一条消息的过程中调用<代码> Apdio.PrimeMase< /代码>时,就会发生这种情况。这一次我的调试感觉在抽搐。即使您没有犯下

    应用程序.ProcessMessages
    sin的错误,您正在显示的表单上的某些组件也可能是错误的

PS:我注意到您在评论中说您已经有了堆栈跟踪。进一步检查堆栈跟踪,看看代码是否是可重入的


由于无法再现该问题,因此需要额外的调试日志来获取更多信息。假设您有一个只附加到调试文件的Log方法。(log方法应输出当前线程ID以确认线程问题。)添加调试日志,如下所示:

Log('Start loop');
for ii := FormListObject.Count - 1 downto 0 do begin
   // Error happens here
   TForm(FormListObject[ii]).Show;
end;
Log('End loop');
封装您的
FormListObject
,以便任何要删除/删除/清除项的代码都通过您控制的代码。也就是说,不要公开对底层列表的直接访问,这将允许流氓代码在您不知情的情况下更改列表。然后在可以删除项目的任何方法上添加日志记录:

Log(Format('(%p)FormListObject.Clear', [Pointer(Self)]));
记录
FormListObject
实例的创建/销毁可能也很有用


当问题发生时,您必须分析日志文件以确定出了什么问题。例如,如果我对问题最可能原因的猜测是正确的,您可能会发现以下模式(注意,每个条目都在同一个线程上):


编辑 我增加了第三种可能性;我有预感这是最有可能的原因。

还添加了一些特定的调试建议以缩小范围。

该错误表示您试图访问空列表的第一个位置。你确定没有其他清单会导致这个问题吗?是的,原因就是我想了解的。怎么会发生这种情况呢?我在列表中丢失了一个TForm项,但计数值没有减少。没有其他TList,它没有在其他地方被清除或修改。由于没有访问冲突错误,我想这可能是线程运行时出现的某种同步问题。列表中的表单是否有修改列表的
OnShow
事件?@whosrdaddy没有OnShow事件。该列表也是该单元的私有成员,没有向外部公开的公共属性。请调查所有更改此列表的代码?你在使用线程吗?谢谢你的回答。我有一个堆栈跟踪,我已经知道错误发生在哪里,它是哪个列表,以及它发生的原因(有一个空列表)。我就是不能在我身边复制这种罕见的错误。某些原因导致列表中的TForm项在保留列表计数时消失。代码非常简单,将项目添加到列表中,循环列表中的项目并终止列表。循环中发生错误,没有访问冲突。这里的关键点是,我认为为什么导致从列表中删除某个项目的内容不会减少列表计数?@Alex:列表计数只会在循环开始时计算。在循环期间从列表中删除项目将导致您看到的错误。@mghie循环中没有代码明确地从列表中删除项目。我已经编辑了上面的帖子,以展示这个循环是多么简单。该列表也不会在本单元其他地方清除或修改。唯一的位置是创建列表后填充的位置。名单被销毁了
(Thread X) Start Loop
(Thread X) Start Loop
(Thread X) End Loop
(Thread X) ($........) Clear