在c++中迭代一个向量的正确方法是什么?

考虑这两个代码片段,这一个工作得很好:

for (unsigned i=0; i < polygon.size(); i++) {
    sum += polygon[i];
}

还有这个:

for (int i=0; i < polygon.size(); i++) {
    sum += polygon[i];
}

生成警告:有符号整数表达式和无符号整数表达式之间的比较。

对我来说,无符号变量看起来有点吓人,我知道无符号变量如果使用不当会很危险,所以-这是正确的吗?


当前回答

auto polygonsize = polygon.size(), i=polygonsize;
for (i=0; i < polygonsize; i++) {
    sum += polygon[i];
}

This

uses auto to avoid us worrying about types. It takes any function calls e.g. the size() function call out of the loop to avoid unnecessary repeated function calls. It makes the loop counter available. Purists will want to work with the n'th element with no knowledge of the value of n, and see this as bad. It appears to have an unecessary statement i=polygonsize initializing the loop variable when it's declared, but this should disappear if there is a half decent code optimizer, and is merely to ensure i has the correct type.

我并不是说任何人都应该像我刚才那样编写代码。

我只是提供它作为另一种替代方案,它可以避免担心类型,将函数调用从循环中取出,并使循环计数器可用于更复杂场景中的调试信息等实际工作。

其他回答

模糊但重要的细节:如果你像下面这样说“for(auto it)”,你得到的是对象的副本,而不是实际的元素:

struct Xs{int i} x;
x.i = 0;
vector <Xs> v;
v.push_back(x);
for(auto it : v)
    it.i = 1;         // doesn't change the element v[0]

要修改vector的元素,需要将迭代器定义为引用:

for(auto &it : v)

关于向后迭代,请参阅这个答案。

Iterating forwards is almost identical. Just change the iterators / swap decrement by increment. You should prefer iterators. Some people tell you to use std::size_t as the index variable type. However, that is not portable. Always use the size_type typedef of the container (While you could get away with only a conversion in the forward iterating case, it could actually go wrong all the way in the backward iterating case when using std::size_t, in case std::size_t is wider than what is the typedef of size_type):


使用std::向量

使用迭代器

for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
    /* std::cout << *it; ... */
}

重要的是,对于您不知道定义的迭代器,始终使用前缀增量形式。这将确保您的代码尽可能通用地运行。

使用Range c++ 11

for(auto const& value: a) {
     /* std::cout << value; ... */

使用索引

for(std::vector<int>::size_type i = 0; i != v.size(); i++) {
    /* std::cout << v[i]; ... */
}

使用数组

使用迭代器

for(element_type* it = a; it != (a + (sizeof a / sizeof *a)); it++) {
    /* std::cout << *it; ... */
}

使用Range c++ 11

for(auto const& value: a) {
     /* std::cout << value; ... */

使用索引

for(std::size_t i = 0; i != (sizeof a / sizeof *a); i++) {
    /* std::cout << a[i]; ... */
}

但是,请阅读向后迭代的答案,看看sizeof方法可以解决什么问题。

第一个是类型正确,严格意义上的正确。(如果你想的是,size永远不可能小于零。)不过,这个警告在我看来是一个很好的被忽视的警告。

讲一点历史:

为了表示一个数字是否为负,计算机使用“符号”位。Int是一种有符号的数据类型,这意味着它可以保存正数和负数(大约- 20亿到20亿)。Unsigned只能存储正数(因为它不浪费元数据,所以可以存储更多:0到40亿)。

Std::vector::size()返回一个无符号值,因为向量的长度怎么可能是负的呢?

警告告诉您,不等式语句的右操作数可以比左操作数保存更多的数据。

从本质上讲,如果你有一个超过20亿项的向量,你使用一个整数来索引,你会遇到溢出问题(int将返回到- 20亿)。

四年过去了,谷歌给了我这个答案。在标准c++ 11(又名c++ 0x)中,实际上有一种新的令人愉快的方式来做到这一点(以打破向后兼容性为代价):新的auto关键字。它为您省去了必须显式指定要使用的迭代器类型(再次重复vector类型)的痛苦,而(对编译器来说)显然应该使用哪种类型。v是你的向量,你可以这样做:

for ( auto i = v.begin(); i != v.end(); i++ ) {
    std::cout << *i << std::endl;
}

c++ 11甚至更进一步,提供了一种特殊的语法,用于迭代向量等集合。它消除了写千篇一律的东西的必要性:

for ( auto &i : v ) {
    std::cout << i << std::endl;
}

要在工作程序中查看它,构建一个auto.cpp文件:

#include <vector>
#include <iostream>

int main(void) {
    std::vector<int> v = std::vector<int>();
    v.push_back(17);
    v.push_back(12);
    v.push_back(23);
    v.push_back(42);
    for ( auto &i : v ) {
        std::cout << i << std::endl;
    }
    return 0;
}

在写这篇文章时,当你用g++编译它时,你通常需要通过给出一个额外的标志来设置它与新标准一起工作:

g++ -std=c++0x -o auto auto.cpp

现在你可以运行这个例子:

$ ./auto
17
12
23
42

请注意,关于编译和运行的说明是特定于Linux上的gnu c++编译器的,程序应该是平台(和编译器)独立的。