I am looking for a gcc-supported C++ language extension to enable the allocation of non-zero-based array pointers. Ideally I could simply write:
#include<iostream>
using namespace std;
// Allocate elements array[lo..hi-1], and return the new array.
template<typename Elem>
Elem* Create_Array(int lo, int hi)
{
return new Elem[hi-lo] - lo;
// FIXME what about [expr.add]/4.
// How do we create a pointer outside the array bounds?
}
// Deallocate an array previously allocated via Create_Array.
template<typename Elem>
void Destroy_Array(Elem* array, int lo, int hi)
{
delete[](array + lo);
}
int main()
{
const int LO = 1000000000;
const int HI = LO + 10;
int* array = Create_Array<int>(LO, HI);
for (int i=LO; i<HI; i++)
array[i] = i;
for (int i=LO; i<HI; i++)
cout << array[i] << "\n";
Destroy_Array(array, LO, HI);
}
The above code seems to work, but is not defined by the C++ standard. Specifically, the issue is [expr.add]/4:
When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the expression P points to element x[i] of an array object x with n elements, the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) element x[i + j] if 0 ≤ i + j ≤ n; otherwise, the behavior is undefined. Likewise, the expression P - J points to the (possibly-hypothetical) element x[i − j] if 0 ≤ i − j ≤ n; otherwise, the behavior is undefined.
In other words, behavior is undefined for the line marked FIXME in the code above, because it calculates a pointer that is outside the range x[0..n]
for the 0-based array x
.
Is there some --std=...
option to gcc
to tell it to allow non-zero-based array pointers to be directly calculated?
If not, is there a reasonably portable way to emulate the return new Type[hi-lo] - lo;
statement, perhaps by casting to long
and back? (but then I would worry about introducing more bugs)
Furthermore, can this be done in a way that requires only 1 register to keep track of each array, like the code above? For example if I have array1[i], array2[i], array3[i]
this requires only the 3 registers for the array pointers array1, array2, array3
, plus one register for i
? (similarly, if cold-fetching the array references, we should be able to just fetch the non-zero-based pointer directly, without doing calculations merely to establish the reference in registers)