我很难在索引类型之间进行选择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
,并且在某些机器中,该上限小于 的最大值size_t
。
IEstd::numeric_limits<std::ptrdiff_t>::max() < std::numeric_limits<std::size_t>::max()
因此,问题是用户可能会创建一个大小大于最大值的数组ptrdiff_t
(但仍然在 的范围内size_t
,当然),但他将无法访问成功超过的数组元素的最大值ptrdiff_t
,因为它们的索引会溢出到负数。在我的机器上,这将可用索引减半!(因为size_t
和ptrdiff_t
都是 64 位,但一个是unsigned
另一个是signed
)
以下是我想出的解决方案,但遗憾的是它们都不是完美的:
在构造函数中,接受 type 的长度
ptrdiff_t
而不是size_t
,并添加一个检查以验证给定的长度是否为负数。优点:它解决了这个问题,因为现在我将能够访问数组中的所有元素,并且仍然允许负索引。
缺点:它限制了数组的最大可能长度。(例如,就像我之前说的,在我的机器中它减半)
保持原样,但在 中
[] operator
,将索引转换为 typesize_t
,并利用负值会溢出的事实。即到给定的索引,添加我们当前指向的元素和
例如,在我之前的示例中,由于 vec2 指向数组中的第二个元素,因此
[] 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]; }
优点:我们现在可以访问数组中的所有元素。
缺点:使用变得笨拙和丑陋。例如,如果我们创建一个 size 的向量
std::numeric_limits<std::size_t>::max()
,那么为了访问最后一个元素,我们需要访问 '-1' 元素:MyVector<int> big_vector(std::numeric_limits<std::size_t>::max()); big_vector[-1] = 5; // big_vector[-1] is the last element in the array. MyVector<int> big_vector2 = big_vector + 1; std::cout << big_vector2[-2] << std::endl; // would print 5, since big_vector2 points at the second element in the array