EListError列表索引超出范围(0) - TForm项目

时间:2014-05-01 15:24:38

标签: delphi tlist

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

我得到的错误是TList个对象:" [EListError]列表索引越界(0)"。 TList包含少量TForm个对象,我们将其隐藏,然后在该操作后立即将其添加到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项,死引用应该触发访问冲突错误,不是吗?

2 个答案:

答案 0 :(得分:3)

  

我得到的错误是在TList对象上:" [EListError]列表索引越界(0)"。

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

使用调试器告诉您哪个列表为空。获取调试器以打破异常。然后尝试找出为什么你的代码假定列表不是空的时候不是这样。

答案 1 :(得分:3)

三个可能的原因:

  • 内存覆盖恰好覆盖"可访问"记忆(所以没有AV)。但是会触发对FormListObject无效的更改。

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

  • 重入代码导致在循环中间更改FormListObject。当您在处理另一条消息时调用Application.ProcessMessages时会发生这种情况。 我的调试感正在抽搐。即使您不对Application.ProcessMessages罪行感到不满,您表现形式上的某些组成部分也可能是。

  

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个实例的创建/销毁可能也很有用。


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

(Thread X) Start Loop
(Thread X) Start Loop
(Thread X) End Loop
(Thread X) ($........) Clear

修改

我增加了第三种可能性;我实际上有预感是最可能的原因 还添加了一些特定的调试建议以缩小范围。