Appending one element to a dynamic array

前端 未结 8 2208
太阳男子
太阳男子 2020-12-05 05:16

This is a very frequent pattern throughout my code:

SetLength(SomeDynamicArray, Length(SomeDynamicArray)+1);
SomeDynamicArray[High(SomeDynamicArray)] := NewE         


        
8条回答
  •  情话喂你
    2020-12-05 06:08

    Every time you call SetLength the memory gets reallocated. Maybe the entire array needs to be copied to a different location. And you who just wanted to add a single element to the array!

    Basically: never do this. There are two ways out of it. The simplest case is if you beforehand know the maximum size of the array:

    procedure Example1;
    var
      data: array of string;
      ActualLength: integer;
    
      procedure AddElement(const Str: string);
      begin
        data[ActualLength] := Str;
        inc(ActualLength);
      end;
    
    begin
    
      ActualLength := 0;
      SetLength(data, KNOWN_UPPER_BOUND);
    
      for ...
        while ...
          repeat ...
            AddElement(SomeString);
    
      SetLength(data, ActualLength);
    
    end;
    

    Here is a practial example of this approach.

    If you don't know any upper bound a priori, then allocate in large chunks:

    procedure Example2;
    const
      ALLOC_BY = 1024;
    var
      data: array of string;
      ActualLength: integer;
    
      procedure AddElement(const Str: string);
      begin
        if ActualLength = length(data) then
          SetLength(data, length(data) + ALLOC_BY);
    
        data[ActualLength] := Str;
        inc(ActualLength);
      end;
    
    begin
    
      ActualLength := 0;
      SetLength(data, ALLOC_BY);
    
      for ...
        while ...
          repeat ...
            AddElement(SomeString);
    
      SetLength(data, ActualLength);
    
    end;
    

    This second approach is implemented in the run-time library's TList, TObjectList, TStringList etc. Hence, when you use these classes, it is perfectly fine to append the list one item at a time.

提交回复
热议问题