用于循环计数的有符号与无符号值

nic*_*ole 14 c++ int vector size-t

所以我在一个程序中有一个普通的for循环通过一个对象向量(对象是我定义的类型,如果相关的话):

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

...当我编译时,我得到这个警告:

warning: comparison between signed and unsigned integer expressions 
Run Code Online (Sandbox Code Playgroud)

这是有道理的,因为我认为size()一个向量返回一个size_t.但为什么重要呢?不是一定数量的元素(甚至是内存块)是一个可以计算的整数吗?更重要的是,由于我的程序有多个这样的循环并且发生了很多段错误,这可能是它的一部分吗?

Gre*_*ill 11

object.size()返回一个大于最大可表示值的k值时会出现问题.自k签名以来,与size_t1相比,它只有最大值的一半.

现在,这可能不会发生在您的特定应用程序中(在典型的32位系统上,您的集合中将有超过20亿个对象),但使用正确的类型总是一个好主意.

1.先发制人的反驳:是的,这仅适用于使用典型二进制补码算法的机器,int以及size_t使用相同位数表示的机器.


ric*_*ici 11

已经很好地回答了,但我会添加我的S/0.02:"正确"的方法是:

for (typename std::vector<MyObject>::size_type i = 0; i < object.size(); ++i) { ... }
Run Code Online (Sandbox Code Playgroud)

只有有抱负的语言律师会写这个,甚至他们可能会在他们找到好东西之前停止阅读.

使用C++ 11,您可以利用decltype:

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

或者你可以利用auto:

for (auto i = object.size() - object.size(); i < object.size(); ++i) { ... }
Run Code Online (Sandbox Code Playgroud)

或者您可以使用size_t,但您仍然可能对溢出有疑问,因为vector<MyObject>size_type可能大于size_t.(不是,但没有保证):

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

那么一个诚实的程序员要做什么?

绝对最简单的解决方案是STL从一开始就一直在推广的解决方案.除了在开始之外,写作也是一种痛苦:

for (typename std::vector<MyObject>::iterator_type it = object.begin(); it != object.end(); ++it) { ... }
Run Code Online (Sandbox Code Playgroud)

现在,C++ 11确实对你有帮助.你有一些非常好的选择,从简单开始:

for (auto it = object.begin(); it != object.end(); ++it) { ... }
Run Code Online (Sandbox Code Playgroud)

但它变得更好(鼓,请)...:

for (auto& val : object) { ... }
Run Code Online (Sandbox Code Playgroud)

这就是我使用的那个.


编辑添加:

Cory Nelson在评论中指出,也可以将object.end()的结果缓存为:

for (auto it = object.begin(), end = object.end(); it != end; ++it) { ... }
Run Code Online (Sandbox Code Playgroud)

事实证明,for (var : object)语法生成的代码与Cory Nelson提出的代码非常相似.(所以我鼓励他和你只使用后者.)

然而,这与其他语义略有不同,包括作为原始帖子主题的迭代.如果您在迭代期间以改变其大小的方式修改容器,那么您必须仔细考虑事情.灾难很有可能发生.

迭代可能在迭代期间被修改的向量的唯一方法是使用整数索引,如在原始帖子中那样.其他容器更宽容.您可以使用循环迭代STL映射,该循环在每次迭代时调用object.end(),并且(据我所知)它甚至可以在插入和删除时使用,但是不要尝试使用unordered_map,或矢量.如果你总是在末端推动并在前面弹出,它确实可以使用双端队列,如果你在广度优先的步行中使用双端队列作为队列,这很方便; 我不确定你能不能在后面弹出双端队列.

在迭代器和元素指针(它们并不总是与迭代器相同)的容器类型容器类型的影响下,确实应该有一个简单的总结,因为这都是标准规定的,但我从来没有碰到它任何地方.如果你找到一个,请告诉我.