我难以在size_t
和ptrdiff_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_t
和size_t
都是64位,但一个是ptrdiff_t
,另一个是unsigned
)
以下是我提出的解决方案,但遗憾的是没有一个是完美的:
在构造函数中,接受signed
类型的长度而不是ptrdiff_t
,并添加一个检查,确认给定的长度不是负数。
优点:它解决了这个问题,因为现在我可以访问数组中的所有元素,但仍允许使用负数索引。
缺点:它限制了数组的最大可能长度。 (例如我之前说的,在我的机器中它减半)
保持原样,但在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()
答案 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
索引该类。