GetMem always allocates memory, FreeMem always releases/frees memory, ReallocMem may do one, the other, or both. In fact, when used properly, ReAllocMem is really the only memory management API needed. If you start with a nil pointer, and call ReAllocMem with a size > 0, then it acts like GetMem. If you call ReAllocMem with size = 0, then it acts like FreeMem. The only time it actually "re-allocates" memory is if the pointer is non-nil and the size > 0.
New and Dispose are designed to work with typed pointers or for you "old-skool" folks, the older Turbo Pascal object model (the old "object) syntax. New and Dispose will also ensure that any typed pointer that is a reference to a managed type will properly initialize that type. For instance given the following:
type
PMyRec = ^TMyRec;
TMyRec = record
Name: string;
Value: Variant;
end;
var
Rec: PMyRec;
begin
New(Rec);
try
Rec.Name := 'TestValue';
Rec.Value := 100;
...
finally
Dispose(Rec);
end;
end;
New and Dispose will ensure that the Name and Value fields of the record are properly initialized and finalized or cleaned-up. New and Dispose, in the above case is equivalent to:
GetMem(Rec, SizeOf(Rec^));
Initialize(Rec);
...
Finalize(Rec);
FreeMem(Rec);
For the example you gave, Gamecat is right, you would probably be better off using a dynamic array since they are better managed by the compiler and they also carry their own intrinsic length. With your example, you would have to separately keep track of the number of items in the array, such that wherever you passed around the array, you'd also have to pass around the currently allocate length. By using a dynamic array, all the information is kept neatly packaged together. This would allow you to iterate over the array regardless of the current length by simply doing one of the following:
var
Member: TMemberData;
Items: array of TMemberData;
...
begin
SetLength(Items, Value);
for Member in Items do // iterate over each element in the array
...
for Low(Items) to High(Items) do // same as above only using std functions
...
end;
Finally, another reason you would probably want to use a dynamic array is that if TMemberData contained strings, variants, interfaces or other "managed" types, they will be properly initialized and finalized without the need to do that manually.