在使用STL容器时,我应该使用int还是unsigned int?

Mar*_*Mao 13 c++ warnings integer stl casting

请参阅本指南:http:
//google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showone = Integer_Types #Integer_Types

谷歌建议int大部分时间使用.
我尝试遵循本指南,唯一的问题是STL容器.

例如:
1.

void SetElement(int Index, int Value)
{
    if (Index > Vector.size()) return;
    ...
}
Run Code Online (Sandbox Code Playgroud)

如果我用intIndex,我得到了一个警告这里.

2.

for (int i = 0; i < Vector.size(); ++i)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

说到循环计数器,同样的警告.

如果我声明Indexiunsigned int它传播,我必须声明更多变量,unsigned int并且不会有一致性.

我能想到的最好的方法是使用像:
if (Index > static_cast<int>(Vector.size()) ...或者
for (int i = 0; i < static_cast<int>(Vector.size()); ++i) ...
我真的不喜欢演员.

有建议的方法吗?

PS
还有更多的理由比链接给出的for循环示例.
要仅使用有符号整数,我可以避免有符号/无符号警告,强制转换,
并确保每个值都可以是负数(为了保持一致),
并且我总是可以使用-1作为无效值.

在许多情况下,它将循环计数器与某个常量或结构成员混合等.
如果有符号/无符号不一致,那么总会有警告和强制转换,
这很烦人且没有意义.
这就是为什么我要统一所有要签名的整数.

Dav*_*vid 11

无符号类型有三个特征,其中一个在质量上 "好",其中一个在质量上 "坏":

  • 它们可以容纳两倍于相同大小的签名类型的值(好)
  • size_t版本(即,在32位机器上的32位,64位的机等在64位)是一个用于表示存储器(地址,大小等)有用(中性)
  • 它们包含在0以下,因此在循环中减去1或使用-1来表示无效索引可能会导致错误(错误.) 签名类型也会包装.

由于上面的前两点,STL使用无符号类型:为了不限制类似数组的类的潜在大小,例如vectordeque(尽管你必须质疑在数据结构中你想要4294967296元素的频率); 因为负值永远不会成为大多数数据结构的有效索引; 因为size_t是用于表示与内存有关的任何东西的正确类型,例如结构的大小,以及相关的东西,例如字符串的长度(见下文).这不一定是将它用于索引或其他的好理由非内存目的,例如循环变量.在C++中这样做的最佳实践是一种反向构造,因为它是容器中使用的以及其他方法,并且一旦使用,其余代码必须匹配以避免遇到的相同问题.

当值可以变为负数时,您应该使用带符号的类型.

当值不能变为负数时,您应该使用无符号类型(可能与'不应该'不同).

您应该size_t在处理内存大小时使用(结果sizeof通常是字符串长度等).它通常被选为要使用的默认无符号类型,因为它与编译代码的平台相匹配.例如,字符串的长度是size_t因为字符串只能有0个或更多元素,并且没有理由将字符串的长度方法任意限制为比平台上可以表示的长度方法短,例如16位长度(0-65535)在32位平台上.注意(感谢评论者Morwen)std::intptr_tstd::uintptr_t概念上相似的 - 对于您的平台来说总是合适的大小 - 并且如果您想要的东西不是指针,则应该用于内存地址.注2(感谢评论者rubenvb)一个字符串只能size_t-1由于值而保存元素npos.详情如下.

这意味着如果使用-1表示无效值,则应使用有符号整数.如果使用循环向后迭代数据,如果您不确定循环结构是否正确,则应考虑使用有符号整数(并且如其他一个答案中所述,它们很容易出错.)IMO ,你不应该采用技巧来确保代码的工作 - 如果代码需要技巧,那通常是一个危险的信号.此外,对于那些关注您并阅读您的代码的人来说,更难理解.这两个都是不遵循@Jasmin Gray的答案的原因.

迭代器

但是,使用基于整数的循环迭代数据结构的内容是在C++中执行它的错误方法,所以从某种意义上说,有符号vs无符号for循环的参数是没有实际意义的.您应该使用迭代器:

std::vector<foo> bar;
for (std::vector<foo>::const_iterator it = bar.begin(); it != bar.end(); ++it) {
  // Access using *it or it->, e.g.:
  const foo & a = *it;
Run Code Online (Sandbox Code Playgroud)

当你这样做时,你不需要担心演员表,签名等.

迭代器可以向前(如上所述)或反向,用于向后迭代.使用相同的语法it != bar.end(),因为它end()表示迭代的结束,而不是底层概念数组,树或其他结构的结束.

换句话说,回答你的问题'在使用STL容器时我应该使用int还是unsigned int?' 是'都不是.改为使用迭代器. 了解更多:

还剩什么?

如果你不使用整数类型的循环,剩下什么?您自己的值,取决于您的数据,但在您的情况下包括使用-1表示无效值.这很简单.使用签名.只是保持一致.

我非常相信使用自然类型,例如枚举,以及适合此的有符号整数.它们更符合我们的概念期望.当你的思想和代码对齐时,你不太可能编写错误的代码,更有可能表达性地编写正确,干净的代码.

  • 好的迭代器和基于范围的`for`s当然很好,有时你只是不能逃脱使用索引,同时迭代2个或更多容器和类似的东西.(它可以用迭代器完成,但是有太多额外的代码,实际上可能不太容易理解).而实际上困扰我有关签名/无符号问题的事情是,如果你使用`unsigned`作为索引进行循环,然后将其更改为以相反顺序迭代,则会导致非显而易见的错误. (4认同)
  • Jamin Gray 的答案不是_以上_。在使用“上方”或“下方”指代本网站上的其他答案时必须小心,因为此类引用可能会因投票而无效。 (2认同)