【问题标题】:Delphi XE8 bug in TList<T>, need workaroundTList<T> 中的 Delphi XE8 错误,需要解决方法
【发布时间】:2015-07-06 13:18:15
【问题描述】:

升级到 XE8 后,我们的一些项目开始破坏数据。看起来像 TList 实现中的一个错误。

program XE8Bug1;
{$APPTYPE CONSOLE}

uses
  System.SysUtils, Generics.Collections;

type
  TRecord = record
    A: Integer;
    B: Int64;
  end;

var
  FRecord: TRecord;
  FList: TList<TRecord>;

begin
  FList := TList<TRecord>.Create;
  FRecord.A := 1;
  FList.Insert(0, FRecord);
  FRecord.A := 3;
  FList.Insert(1, FRecord);
  FRecord.A := 2;
  FList.Insert(1, FRecord);
  Writeln(IntToStr(FList[0].A) + IntToStr(FList[1].A) + IntToStr(FList[2].A));

end.

此代码在 XE7 和之前的版本中打印“123”(应该如此),但在 XE8 中它打印“120”。 也许有人知道这个的快速修复?

更新:非官方修复是here

【问题讨论】:

  • 通用集合已在 XE8 中重新实现。也许他们在 Emba 没有任何单元测试。如果这是您所描述的,并且看起来很可能,您的解决方案是保留在 XE7 上。您确实需要提交错误报告。
  • 因此,Embarcadero 似乎没有有效的测试制度。他们到底怎么会弄错这个?这样的基础课。一个运行良好的开发团队会对此进行全面的单元测试。这样的故障不应该通过测试。惨淡。
  • 而且我必须支付额外费用才能修复这个(4 周前)产品的错误。
  • 相关:stackoverflow.com/questions/30850911/… 我猜他们认为没有人需要使用Insert,所以他们从未测试过。

标签: delphi generics tlist delphi-xe8


【解决方案1】:

我发现现在TList&lt;T&gt;.Insert 方法调用TListHelper.InternalInsertX 取决于数据大小,就我而言:

procedure TListHelper.InternalInsertN(AIndex: Integer; const Value);
var
  ElemSize: Integer;
begin
  CheckInsertRange(AIndex);

  InternalGrowCheck(FCount + 1);
  ElemSize := ElSize;
  if AIndex <> FCount then
    Move(PByte(FItems^)[AIndex * ElemSize], PByte(FItems^)[(AIndex * ElemSize) + 1], (FCount - AIndex) * ElemSize);
  Move(Value, PByte(FItems^)[AIndex * ElemSize], ElemSize);
  Inc(FCount);
  FNotify(Value, cnAdded);
end;

我在第一个Move 电话中看到了问题。目的地应该是:

PByte(FItems^)[(AIndex + 1) * ElemSize]

不是

PByte(FItems^)[(AIndex * ElemSize) + 1]

啊!

最后,我在项目中使用了 Delphi XE7 中的 System.Generics.Defaults.pas 和 System.Generics.Collections.pas 单元,现在一切正常。

更新:正如我所见,RTL 不受影响,因为它不使用 TList&lt;T&gt;.Insert 用于 SizeOf > 8 的 T(或者我可能错过了什么?)

【讨论】:

  • 通过恢复 XE7 实现进行修复并不是一个坏主意。你对它更有信心。是的,你可以修补这个方法,但你不知道他们还有什么问题吗?
  • 虽然如果你更换整个单元,这样做是明智的,这意味着 RTL/VCL/FMX 等也使用固定单元。否则,您可能会受到此缺陷的其他表现形式的伤害。
  • 没有经验的开发人员的口头禅:“为什么要查看旧代码,当您可以以'更好'的方式编写新代码时”;-)(我有太多这样的开发人员,令人失望的是 Embarcadero 拥有他们)
  • RTL中有很多很多地方用到了TList.Insert。这到底怎么可能不被发现?
  • @BofA SizeOf(T)&gt;8 并且该类型是非托管的。也许 Emba 通过更喜欢 dyn 分配的类而不是自动分配的记录来摆脱它。
猜你喜欢
  • 2017-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-07
  • 1970-01-01
  • 2013-03-10
  • 2015-01-15
  • 1970-01-01
相关资源
最近更新 更多