Ошибка Delphi XE8 в TList <T>, требуется обходной путь

38

После обновления до 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.

Этот код печатает "123" в XE7 и раньше (как и должно быть), но в XE8 он печатает "120". Может быть, кто-то знает, что это значит?

Обновление: Неофициальное исправление здесь

  • 9
    Общие коллекции были повторно реализованы в XE8. Возможно, у них нет юнит-тестов в Эмбе. Если это так, как вы описываете, и кажется вероятным, ваше решение - остаться на XE7. Вам необходимо отправить сообщение об ошибке.
  • 3
    Отмечено как регрессия: TList <T>. Вставка не работает .
Показать ещё 5 комментариев
Теги:
generics
delphi-xe8
tlist

1 ответ

30
Лучший ответ

Я обнаружил, что теперь вызов метода TList<T>.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]

not

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

Aaargh!

Наконец, я использовал модули System.Generics.Defaults.pas и System.Generics.Collections.pas из Delphi XE7 в своих проектах, и теперь все работает как ожидалось.

Обновление: как я вижу, RTL не затрагивается, так как он не использует TList<T>.Insert для T с SizeOf > 8 (или, может быть, я что-то пропустил?)

  • 0
    Патч метод, и вы работаете.
  • 3
    Исправление путем восстановления реализации XE7 не такая уж плохая идея. Вы больше доверяете этому. Да, вы можете исправить этот один метод, но вам не интересно, что еще они ошиблись?
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню