delphi generics tlist delphi-xe8

Fallo de Delphi XE8 en TList<T>, necesita una solución alternativa



generics delphi-xe8 (1)

Después de actualizar a XE8 algunos de nuestros proyectos comienzan a romper datos. Parece un error en la realización de 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.

Este código imprime "123" en XE7 y antes (como debería ser), pero en XE8 imprime "120". Tal vez alguien sepa una solución rápida para esto?

Actualización: solución no oficial está here


Descubrí que ahora el TList<T>.Insert método llamado TListHelper.InternalInsertX depende del tamaño de los datos, en mi caso:

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;

Veo el problema en la primera llamada de Move . El destino debe ser:

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

no

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

Aaargh!

Finalmente, he usado las unidades System.Generics.Defaults.pas y System.Generics.Collections.pas de Delphi XE7 en mis proyectos, y ahora todo funciona como esperaba.

Actualización: como veo, RTL no se ve afectado, ya que no se usa TList<T>.Insert para T con SizeOf> 8 (¿o tal vez me pierdo algo?)