【问题标题】:EListError List index out of bounds (0) - TForm itemEListError List index out of bounds (0) - TForm 项
【发布时间】:2014-05-01 15:24:38
【问题描述】:

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

我得到的错误是在 TList 对象上:“[EListError] List index out of bounds (0)”。 TList 包含很少的 TForm 对象,我们使它们不可见,然后在该操作之后将它们添加到 TList。现在我们想让它们再次可见并释放,然后将 TList 设为 nil。当我们想让表单再次可见时会发生错误。

所以有一个循环,TList.Count 有一个值。代码进入循环并发生上述错误。上面的错误不是意味着特定索引处没有项目但列表计数大于零,怎么可能?

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

for ii := FormListObject.Count - 1 downto 0 do begin
   // Error happens here
   TForm(FormListObject[ii]).Show;
end;

您认为这是 gui 线程问题、子项问题还是某种形式的表单被破坏/杀死并且列表有无效引用?我仍然认为这个错误意味着索引 0 处没有 TList 项,死引用应该触发访问冲突错误,不是吗?

【问题讨论】:

  • 该错误意味着您正在尝试访问空列表的第一个位置。您确定没有其他可能导致问题的列表吗?
  • 是的,原因是我试图理解的事情。怎么会发生这种情况,我在列表中丢失了一个 TForm 项,但计数值没有减少。没有其他 TList,它没有在其他地方清除或修改。而且由于没有访问冲突错误,我在想这可能是线程运行的某种同步问题。
  • 列表中的表单是否有修改列表的OnShow事件?
  • @whosrdaddy 不,没有 onShow 事件。该列表也是该单元的私有成员,没有将其暴露在外部的公共财产。
  • 请调查所有更改此列表的代码?你在用线程吗?

标签: delphi tlist


【解决方案1】:

三种可能的原因:

  • 内存覆盖恰好覆盖“可访问”内存中的内容(因此没有 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,以便任何用于删除/删除/清除项目的代码都在您的控制下通过代码。 IE。不要公开对底层列表的直接访问,这将允许流氓代码在没有您知识的情况下更改列表。然后在可以删除项目的任何方法上添加日志记录:

Log(Format('(%p)FormListObject.Clear', [Pointer(Self)]));

记录FormListObject 实例的创建/销毁也可能很有用。


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

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

编辑

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

【讨论】:

  • 我在这里提出了这个问题,以了解可能导致这种情况的一些想法。我需要进一步调查,也许会使用日志记录。我也会记住所有这些想法。谢谢
【解决方案2】:

我得到的错误是在 TList 对象上:“[EListError] List index out of bounds (0)”。

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

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

【讨论】:

  • 感谢您的回答。好吧,我有一个堆栈跟踪,我已经知道错误发生在哪里,它是哪个列表以及它发生的原因(有一个空列表)。我只是无法在我身边复制这个罕见的错误。在保留列表计数时,某些东西会导致我列表中的 TForm 项目消失。代码非常简单,将项目添加到列表中,循环列表中的项目并终止列表。错误发生在循环中,没有访问冲突。这里的关键是我认为为什么会导致从列表中删除项目的东西不会减少列表计数?
  • @Alex:列表计数将仅在循环开始时进行评估。在循环期间从列表中删除项目将导致您看到的错误。
  • @mghie 循环中的代码没有从列表中删除任何项目。我已经编辑了我上面的帖子,以展示这个循环是多么简单。该列表也不会在本单元的其他任何地方清除或修改。唯一的位置是创建列表后填充的位置。列表在循环后立即被销毁,我有错误。
  • @Alex:太好了,你发现了这个错误 - 可能没有什么“导致从列表中删除的项目不会减少列表计数”?如果是这样,我确实有兴趣了解它。
  • 显然有些东西正在从列表中删除项目。
猜你喜欢
  • 1970-01-01
  • 2012-12-26
  • 1970-01-01
  • 2021-05-07
  • 2013-04-27
  • 2012-01-18
  • 2017-05-20
  • 2017-04-09
  • 1970-01-01
相关资源
最近更新 更多