2015-04-27 6 views
38

Dopo l'aggiornamento a XE8 alcuni dei nostri progetti iniziano a suddividere i dati. Sembra un bug nella realizzazione di TList.Bug Delphi XE8 in TList <T>, è necessario risolvere il problema

stampe
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. 

questo codice "123" in XE7 e prima (come dovrebbe essere), ma in XE8 esso stampa "120". Forse qualcuno conosce un quickfix per questo?

Aggiornamento: fix non ufficiale è here

+9

Le collezioni generici sono stati ri-implementato in XE8. Forse non hanno alcun test unitario all'Emba. Se questo è come descrivi, e sembra probabile, la tua soluzione è rimanere su XE7. Devi presentare una segnalazione di bug. –

+3

Segnalato come [Regressione: TList .Inserimento non funzionante] (https://quality.embarcadero.com/browse/RSP-10773). –

+10

Quindi sembra che l'Embarcadero non abbia un regime di test efficace. Come diavolo avrebbero potuto sbagliare? Una classe così fondamentale. Un team di sviluppo ben gestito avrebbe testato questo apparecchio in modo completo. Tale errore non dovrebbe mai superare questo test. Triste. –

risposta

32

ho scoperto che ora il TList<T>.Insert chiamata di metodo TListHelper.InternalInsertX dipende dalla dimensione dei dati, nel mio 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; 

vedo il problema, in primo Move chiamata. Destinazione dovrebbe essere:

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

non

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

Aaargh!

Infine, ho utilizzato le unità System.Generics.Defaults.pas e System.Generics.Collections.pas da Delphi XE7 nei miei progetti, e ora tutto funziona come previsto.

Update: come la vedo io, RTL non è influenzato, in quanto non è utilizzare TList<T>.Insert per T con SizeOf> 8 (o forse mi manca qualcosa?)

+0

Applica il metodo e sei attivo e in esecuzione. –

+3

La correzione ripristinando l'implementazione XE7 non è una cattiva idea. Hai più fiducia in esso. Sì, puoi applicare questo metodo, ma non ti chiedi che altro hanno sbagliato? –

+1

Anche se si sostituiscono le unità intere, sarebbe opportuno farlo in un modo che significa che RTL/VCL/FMX ecc. Usano anche le unità fisse. Altrimenti potresti essere ferito da altre manifestazioni di questo difetto. –

Problemi correlati