【发布时间】:2019-03-01 20:40:59
【问题描述】:
我正在寻找支持 gcc 的 C++ 语言扩展来启用非从零开始的数组指针的分配。理想情况下,我可以简单地写:
#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);
}
上面的代码似乎可以工作,但不是由 C++ 标准定义的。具体来说,问题是[expr.add]/4:
当具有整数类型的表达式被添加或减去时 从一个指针,结果具有指针操作数的类型。如果 表达式 P 指向具有 n 的数组对象 x 的元素 x[i] 元素,表达式 P + J 和 J + P(其中 J 的值为 j) 如果 0 ≤ i + j ≤ 则指向(可能是假设的)元素 x[i + j] n; 否则,行为未定义。同样,表达式 P - J 指向(可能是假设的)元素 x[i - j] 如果 0 ≤ i - j ≤ n;否则,行为未定义。
换句话说,上面代码中标记为 FIXME 的行的行为是未定义的,因为它为基于 0 的数组 x 计算了一个超出范围 x[0..n] 的指针。
gcc 是否有一些 --std=... 选项来告诉它允许直接计算非零基数组指针?
如果没有,是否有一种合理的可移植方式来模拟return new Type[hi-lo] - lo; 语句,也许是通过转换为long 并返回? (但我会担心引入更多错误)
此外,是否可以像上面的代码那样只需要 1 个寄存器来跟踪每个数组?例如,如果我有array1[i], array2[i], array3[i],这只需要数组指针array1, array2, array3 的3 个寄存器,加上i 的一个寄存器? (类似地,如果冷取数组引用,我们应该能够直接获取非从零开始的指针,而不需要仅仅为了在寄存器中建立引用而进行计算)
【问题讨论】:
-
只需创建一个数组/向量类,它在食物下使用 0 索引,但将用户索引范围作为其
operator []。对于每一个问题,都有一个抽象可以解决它:) -
@François Andrieux 好点。我已经删除了语言律师标签。
-
@NathanOlivier 好的,但是
operator[]不会包含像array[offset + i]这样的表达式,这不是表示每个数组所需的寄存器数量的两倍吗?我在问题中添加了一句话来阐明效率目标。 -
@personal_cloud 我怀疑不是。只是没有用于规避每个不方便的 c++ 规则的扩展。这些规则的存在通常是有原因的,如果绕过它们很容易,那么它们可能一开始就不需要存在。
-
@personal_cloud 这个问题本身已经确定,它违反了语言规则。如果您要问的是为什么 或什么段落禁止这样做,那么这将是一个语言律师问题,但这将是一个独特的问题。这个问题的答案似乎只是“没有这样的扩展/保证”或“是的,使用[编译器标志]”。编辑:在您的最后评论之后,这可能是一个语言律师问题。例如,“指针是否需要有效才能使用运算符
[]”。但这是一个不同的问题。
标签: c++ arrays gcc allocation