Suppose I have the following function that uses
Move to copy an open array to the heap:
type
TVarRecArray = array of TVarRec;
function Box(const Items: array of const): TVarRecArray;
begin
Result := Nil;
SetLength(Result, Length(Items));
Move(Items[0], Result[0], Length(Items) * SizeOf(Items[0]));
end;
When enabling range checks, the arguments to
Move cause problems when
Items contains no elements, because the compiler (and everyone who doesn't know
Move's signature, really) doesn't realize that
Items[0] and
Result[0] involve no actual memory accesses, but only innocuous address calculations (that never get dereferenced anyway).
Now, my question is:
Is there any way to get a reference to the first element of an array for use with Move that doesn't trigger range checks and works with all array types?I don't want to toggle range checks off/on with
{$push}{$R-} [...] {$pop} for every offending expression, and I don't want to introduce unnecessary branching for code that's perfectly safe.
Pointer casts break in the worst possible way when a dynamic array is changed to a non-dynamic one and vice versa (for reference, in this example
Pointer(@Items)^ would work only because
Items is an open array; if it were changed to a dynamic array, that expression would cause
Move to pull undefined data from the stack -
Pointer(Items)^ is what's needed for dynamic arrays).