You're not going to initialize memory for each element. If you want that, use a linked list instead.
Initialize is always called on each element, just normally it is hidden by compiler magic. TList from Generics.Collections for example uses "array of T" and allocates the memory with Setlength, which will internally call Initialize for each element.
You *always* need to initialize the memory for each element. The question is just if it is done automatically, either through a constructor, New or SetLength, or if you need to do it manually which you need to do if you use raw allocation e.g. via getmem, stack allocation or, in case of microcontrollers and you don't have virtual memory, when performing direct memory access.
This can also be easiely tested check the memory consumption of the following two programs:
program Project1;
{$mode objfpc}{$H+}
type
TLargeArray = Array[1..1024*1024*1024 div SizeOf(String)] of String; // 1 GB memory
PLargeArray = ^TLargeArray;
var
p: PLargeArray;
begin
p := GetMem(SizeOf(TLargeArray));
ReadLn;
FreeMem(p);
end.
and
program Project1;
{$mode objfpc}{$H+}
type
TLargeArray = Array[1..1024*1024*1024 div SizeOf(String)] of String; // 1 GB memory
PLargeArray = ^TLargeArray;
var
p: PLargeArray;
begin
New(p);
ReadLn;
Dispose(p);
end.
The first program takes takes up no physical memory at all (only 0.6 MB when launched with debugger symbols), while the second one takes 1GB of memory.
The reason for that is that allocating virtual memory does by itself not use any physical memory, only once a page is touched it is loaded into actual memory. What happens in the second example that implicetly (as part of calling New), the code will iterate over every single element of the array and call initialize on it.
But the first program is not complete yet, you can't use any array element until you called Initialize on it.
As a simple rule of thumb: If you use GetMem, always call Initialize and if you use FreeMem always use Finalize.
PS: You can use this as an alternative to geometric growth, to allocate large chunks of virtual memory in advance but only touch the elements (and call Initialize on them) when you need them (for performance reasons this can also be done in a geometric fashion). If you know the maximum size of the list beforehand, and also have enough virtual memory available (2^48 bytes on most modern x86_64 CPUs) this can improve performance by avoiding multiple calls to the memory managers and also copy operations.