用于负数组索引的C ++ size_t和ptrdiff_t

时间:2015-08-10 08:32:02

标签: c++ arrays indexing size-t ptrdiff-t

我难以在size_tptrdiff_t之间选择索引类型,而该索引应该能够存储负值。

准确地说,在我的代码中我需要实现一个数组。我将它的长度(在构造函数中)作为size_t的类型接收,当我重载[] operator时,我需要索引的类型为ptrdiff_t(而不是size_t),因为我想允许负面索引,如下例所示:

std::size_t length = 50;
MyVector<int> vec(length);
vec[0] = 10;

MyVector<int> vec2 = vec+1;
std::cout << vec2[-1] << std::endl; //should print 10

所述设计产生的问题是可用索引的范围受ptrdiff_t的最大值限制,并且在某些机器中,此上限小于{{的最大值1}} 即可。

即。 size_t

因此,问题是用户可能会创建一个大小大于std::numeric_limits<std::ptrdiff_t>::max() < std::numeric_limits<std::size_t>::max()的最大值的数组(当然,仍然在ptrdiff_t的范围内),但是他无法访问成功超过size_t 最大值的数组元素,因为它们的索引会溢出到负数。在我的机器上,这将可用的索引减少了一半! (因为ptrdiff_tsize_t都是64位,但一个是ptrdiff_t,另一个是unsigned

以下是我提出的解决方案,但遗憾的是没有一个是完美的:

  1. 在构造函数中,接受signed类型的长度而不是ptrdiff_t,并添加一个检查,确认给定的长度不是负数。

    优点:它解决了这个问题,因为现在我可以访问数组中的所有元素,但仍允许使用负数索引。

    缺点:它限制了数组的最大可能长度。 (例如我之前说的,在我的机器中它减半)

  2. 保持原样,但在size_t中,将索引转换为[] operator类型,并利用负值溢出的事实。

    即。到给定的索引,添加我们当前指向的元素和

    之间的差异

    例如,在我之前的例子中,由于vec2指向了arary中的 second 元素,size_t看起来像

    [] operator

    优点:我们现在能够访问数组中的所有元素。

    缺点:使用变得笨拙和丑陋。 例如,如果我们创建一个大小为template<class T> T& MyVector<T>::operator[] (std::ptrdiff_t index) { //Since vec2 points to the second element, we add 1. //For vec, we would add 0 since it points at the //first element in the array. std::size_t actual_index = static_cast<std::size_t>(index + 1); //Do boundary checking return this->ptr[actual_index]; } 的向量,那么为了访问最后一个元素,我们需要访问&#39; -1&#39;元素:

    std::numeric_limits<std::size_t>::max()

1 个答案:

答案 0 :(得分:0)

  

我很难在size_t和ptrdiff_t之间选择索引类型,它应该能够存储负值。

为什么你限制自己的size_t和ptrdiff_t?那么其他整数类型呢?

您是否有实际计划实施具有4.294.967.296元素的容器? (即2 ^ 32)。

我认为今天没有一个平台可以分配那么多内存 - 至少在消费级别的计算机上没有。你在使用专门的硬件吗?

对于通用C ++,您可以安全地将std::size_t - 接受构造函数写入std::ptrdiff_t索引类。

您可能必须配置可接受的索引范围,因此如果您接受负索引,则有效索引范围应为(-max32bit,max32bit)。

这意味着,如果您尝试使用范围内的索引(max32bit,max64bit)的类,则您的类应该抛出异常。

我的解决方案会在构造函数中接受std::size_t(有明确的文档说明索引范围从-max(ptrdiff_t)到max(ptrdiff_t),而不是从0到0 max(std::size_t)。然后使用std::ptrdiff_t索引该类。