问题
Is there a fast way to copy a generic TList?
Copy.Capacity := List.Count;
for Item in List do
Copy.Add (Item);
is very slow. There seems to be no way to use CopyMemory
since I can't get the memory adress of the internal array (which is obvious from an information hiding viewpoint). I miss something like
List.Copy (Copy);
which uses the knowledge of the internal representation to improve performance. Can it be done?
回答1:
For the generic TList<T>
it is simply not possible to implement the function you want. That's because copy the contents of T
may involve more than a simple memory copy. If T
contains any managed types (i.e. strings, interfaces etc.) then the reference counts on those managed objects must be incremented.
- If your
T
does contain managed types then I doubt that you can do much better then the code you already have. - If your
T
does not contain any managed types then a memory copy is viable but you will need to create your own class to encapsulate this list sinceTList<T>
is not appropriate.
回答2:
You always can reinterpret of memory.
type
TListHack<T> = class(TEnumerable<T>)
private
FItems: array of T;
FCount: Integer;
public
class procedure FastAdd(Source, Dest: TList<T>);
end;
{ TListHack<T> }
class procedure TListHack<T>.FastAdd(Source, Dest: TList<T>);
var
SourceHack: TListHack<T>;
DestHack: TListHack<T>;
TI: PTypeInfo;
begin
TI := TypeInfo(T);
if not (TI.Kind in [tkInteger, tkChar, tkFloat,
tkSet, tkClass, tkMethod, tkWChar, tkInt64, tkClassRef, tkPointer, tkProcedure]) then
raise Exception.CreateFmt('Type %s is not supported', [TI.Name]);
if Source.Count = 0 then
Exit;
DestHack := TListHack<T>(Dest);
SourceHack := TListHack<T>(Source);
if Dest.Capacity < Dest.Count + Source.Count then
Dest.Capacity := Dest.Count + Source.Count;
Move(SourceHack.FItems[0], DestHack.FItems[Dest.Count], Source.Count * SizeOf(T));
DestHack.FCount := DestHack.FCount + Source.Count;
end;
procedure TForm6.FormCreate(Sender: TObject);
var
Source, Dest: TList<Integer>;
Arr: TArray<Integer>;
begin
Source := TList<Integer>.Create;
Dest := TList<Integer>.Create;
try
Source.Add(1); Source.Add(2); Source.Add(3);
Dest.Add(10);
TListHack<Integer>.FastAdd(Source, Dest);
Assert(Dest.Count = 4);
ShowMessageFmt('%d, %d, %d, %d', [Dest[0], Dest[1], Dest[2], Dest[3]]);
finally
Source.Free; Dest.Free;
end;
TListHack<IUnknown>.FastAdd(TList<IUnknown>.Create, TLIst<IUnknown>.Create); // exception
end;
But it's very dangerously
来源:https://stackoverflow.com/questions/9479089/fast-copy-of-tlist-t