Using int
从逻辑角度来看,对数组进行索引更正确。
unsigned
C 和 C++ 中的语义并不真正意味着“非负”,但它更像是“位掩码”或“模整数”。
了解原因unsigned
不是“非负”数的好类型请考虑这些完全荒谬的陈述:
- 将一个可能为负的整数与一个非负整数相加,得到一个非负整数
- 两个非负整数之差始终是非负整数
- 将非负整数乘以负整数,得到非负结果
显然上面的短语都没有任何意义...但这就是 C 和 C++ 的方式unsigned
语义确实有效。
实际上使用一个unsigned
容器大小的类型是 C++ 的一个设计错误,不幸的是我们现在注定要永远使用这个错误的选择(为了向后兼容)。您可能喜欢“无符号”这个名称,因为它与“非负”类似,但该名称无关紧要,重要的是语义......并且unsigned
离“非负”还很远。
因此,在对向量上的大多数循环进行编码时,我个人首选的形式是:
for (int i=0,n=v.size(); i<n; i++) {
...
}
(当然假设向量的大小在迭代过程中没有改变,并且我实际上需要主体中的索引,否则for (auto& x : v)...
更好)。
这逃离unsigned
尽快使用纯整数的优点是可以避免由于以下原因而导致的陷阱unsigned size_t
设计错误。例如考虑:
// draw lines connecting the dots
for (size_t i=0; i<pts.size()-1; i++) {
drawLine(pts[i], pts[i+1]);
}
如果上面的代码会出现问题pts
向量为空,因为pts.size()-1
在这种情况下是一个巨大的无意义数字。处理表达式 wherea < b-1
不等于a+1 < b
即使对于常用的值也就像在雷区跳舞一样。
从历史上看,拥有的理由size_t
无符号是为了能够使用值的额外位,例如数组中能够有 65535 个元素,而不是 16 位平台上的 32767 个元素。在我看来,即使在那个时候,这种错误的语义选择所带来的额外成本也是不值得的(如果现在 32767 个元素还不够,那么 65535 个元素无论如何也不会足够长)。
无符号值非常有用,但不能用于表示容器大小或索引;对于大小和索引,常规有符号整数效果更好,因为语义正是您所期望的。
当您需要模算术属性或想要在位级别工作时,无符号值是理想的类型。