已经有很好的回答了,但我也想补充一下我的意见:正确的做法是:
for (typename std::vector<MyObject>::size_type i = 0
只有那些渴望成为语言专家的人才会写出这样的内容,即使他们也可能在阅读到精华之前停下来。使用C++11,您可以利用
decltype
:
for (decltype(object.size()) i = 0
或者您可以利用 auto
:
for (auto i = object.size() - object.size(); i < object.size(); ++i) { ... }
或者你可以直接使用size_t
,但是你仍然可能对溢出有疑虑,因为vector<MyObject>
的size_type可能比size_t
更大。(事实并非如此,但没有保证):
for (size_t i = 0
那么一个诚实的程序员应该怎么做呢?
最简单的解决方案就是STL从一开始就一直在推广的方案。只不过在一开始时,编写这个方案也很麻烦:
for (typename std::vector<MyObject>::iterator_type it = object.begin()
现在,C++11确实对您有所帮助。您有一些非常好的替代方案,从简单的开始:
for (auto it = object.begin(); it != object.end(); ++it) { ... }
但更好的是(请敲鼓声)……:
for (auto& val : object) { ... }
那是我会使用的。
编辑以添加:
Cory Nelson在评论中指出,还可以使用以下代码缓存object.end()的结果:
for (auto it = object.begin(), end = object.end(); it != end; ++it) { ... }
事实证明,for (var : object)
语法生成的代码与 Cory Nelson 提出的代码非常相似(因此我鼓励他和您只使用后者)。然而,它与其他语法具有微妙的不同语义,包括原始帖子所讨论的迭代。如果您在迭代过程中以一种改变容器大小的方式修改容器,则必须非常仔细地考虑问题,否则会引发灾难。
迭代可能在迭代过程中被修改的 vector 的唯一方法是使用整数索引,就像原始帖子中所述的那样。其他容器则更加宽容。您可以使用循环迭代 STL 映射(map),并在每次迭代中调用 object.end(),(据我所知)即使面对插入和删除也能正常工作,但不要尝试在 unordered_map 或 vector 上尝试这样做。如果您总是在结尾推送(push)并在前面弹出(pop),则可以使用 deque 进行迭代,这在广度优先遍历中使用 deque 作为队列时非常方便;我不确定是否可以从 deque 的末端弹出。
实际上应该有一个简单的摘要,概述容器类型对迭代器和元素指针(它们并不总是与迭代器相同)的容器修改的影响,因为这一切都是由标准规定的,但我从未在任何地方找到过。如果您发现了这样的内容,请告诉我。