size_t
和 ptrdiff_t
作为索引类型时遇到了困难,因为它需要能够存储负值。确切地说,在我的代码中,我需要实现一个数组。我在构造函数中以
size_t
类型接收其长度,并且当我重载 [] 运算符
时,我希望索引的类型为 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
的最大值。即
std::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
)以下是我想到的解决方案,但遗憾的是没有一种是完美的:
In the constructor, accept a length of type
ptrdiff_t
instead ofsize_t
, and add a check that verifies that the given length is not negative.Pros: It solves the issue, since now I would be able ot access all the elements in the array, and still allow for negative indexes.
Cons: It limits the maximum possible length of the array. (e.g. like I said earlier, in my machine it cuts by half)
Leave things as they are, but in the
[] operator
, cast the index to typesize_t
, and make use of the fact that negative value would overflow.i.e. to the given index, add the difference between the element we're currently pointing to, and the
for example, in my example before, since vec2 points to the second element in the arary, the
[] operator
would look something liketemplate<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]; }
Pros: We're now able to access all the elements in the array.
Cons: The usage becomes clumsy and ugly. For example, if we create a vector of size
std::numeric_limits<std::size_t>::max()
, then in order to access the last element, we need to access the '-1' element: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
C++
代码是一个更大的问题,需要非常小心和测试,因此在投入过多精力之前,请考虑它是否真的是您的应用程序的要求。 - doynaxptrdiff_t
可能比size_t
小,但这种架构非常罕见。编写完全可移植的C/C++
代码以兼容所有奇怪的系统几乎是不可能的(例如需要大量的注意、笨拙的解决方案和由于非传统平台的稀缺性而几乎不可能进行的测试)。编写C++
代码的典型方式是选择你要支持的实现选择子集,然后在之后重新测试/审查,以确定你的猜测是否正确。大多数代码不需要在 24 位 DSP 上运行。 - doynax