数组索引的类型:有符号/无符号整数优点

Ins*_*oop 5 c c++

在C ++中,数组索引的默认大小为size_t,这是大多数x86-64平台上的64位无符号 64位整数。我正在为自己的高性能计算库构建自己的std :: vector类(主要原因之一是我希望该类能够获得指针的所有权,而std :: vector却没有提供)。对于数组索引的类型,我正在考虑使用以下任一方法:

  • size_t
  • 我自己的index_t将是一个有符号的 int或一个长的有符号的int,具体取决于我的程序

与无符号整数相比,使用有符号整数的优势很多,例如

for (index_t i = 0; i < v.size() - 1; ++i)
Run Code Online (Sandbox Code Playgroud)

的工作方式就像是假设的(使用无符号整数,当v的大小为0时,此循环会变得疯狂)

for (index_t i = v.size() - 1; i >= 0; --i)
Run Code Online (Sandbox Code Playgroud)

像预期的那样工作,还有许多其他优点。在性能方面,它甚至看起来要好一些

a + 1 < b + 1
Run Code Online (Sandbox Code Playgroud)

可以减少为带符号整数的<b(未定义溢出),而对于无符号整数则不能。唯一有利的性能明智的做法是,可以将/ = 2简化为使用无符号整数的移位操作,而不是使用有符号整数的移位操作。

我想知道为什么C ++委员会决定对size_t 使用无符号整数,因为这似乎带来了很多麻烦,并且只有很少的优点。

Jam*_*nze 8

在标准中使用无符号类型作为索引或大小的动机是基于仅与 16 位机器相关的约束。C++ 中任何整数类型的自然类型是 int,这就是可能应该使用的类型;正如您所注意到的,在 C++ 中尝试使用无符号类型作为数值是充满问题的。如果您担心尺寸太大以至于无法放入int,ptrdiff_t 将是合适的;毕竟,这是指针或迭代器相减结果的类型。(事实上​​, v.size()它的类型v.end() - v.begin()与标准库中的设计缺陷不同。)

  • @BaummitAugen 这取决于。没有简单的规则,`std::vector&lt;&gt;::size` 返回一个无符号类型的事实是可悲的,因为它造成了问题。但由于我很少使用 `std::vector&lt;&gt;::size`,所以这不是问题。两个迭代器之间的区别是有符号类型,最终会更频繁地使用。 (4认同)
  • 嗨鲍姆。我只是使用我自己的向量实现。.size() 方法返回一个有符号整数,这使得一切顺利。如果您使用 std::vector,则您承诺使用 std::size_t。 (2认同)

unw*_*ind 4

对我来说,无符号大小总是最有意义的,因为数组中不能有 -32 个元素,因此始终将大小/长度视为有符号数量是非常非常可怕的。

您提到的极端情况可以进行编码,例如,如果第一种情况为空,您可以在进入循环之前中止循环v(这看起来不太常见,迭代除最后一个元素之外的所有元素?)。

  • 索引是一个数值,无符号整型的行为不像数值那样良好。(例如,“abs(i1 - i2)”_不_给出两个索引之间的差异。)理想情况下,索引应该是范围类型,但 C++ 没有范围类型。尝试用“unsigned”来伪造它并没有帮助,因为它仍然使上限范围不受控制。C++ 中的无符号整数类型是为一些非常特定的用途而设计的,例如位操作或真正需要模运算时。 (6认同)
  • 在许多示例中,循环遍历除最后一个元素之外的所有元素可能很有用。我正在考虑冒泡排序或遍历矩阵的元素 M(i, i + 1) (主元素上方的对角线)。我理解“它确实传达了一个消息,即整数是非负的”,但大多数人都使用 int 来遍历 C 中的数组,并且对 int 感觉很好。 (4认同)