迭代std :: vector:unsigned与有符号的索引variables

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

考虑这两个代码片段,这个工作正常:

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

和这个:

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

这会产生warning: comparison between signed and unsigned integer expressions

我是C ++世界中的新成员,所以unsignedvariables对我来说看起来有些可怕,而且我知道,如果使用不正确, unsignedvariables可能是危险的,所以 – 这是正确的吗?

向后迭代

看到这个答案 。

迭代前锋

这几乎是相同的。 只需按增量更改迭代器/交换减量。 你应该更喜欢迭代器。 有些人告诉你使用std::size_t作为索引variablestypes。 但是,这不是便携式的。 总是使用容器的size_type typedef(虽然在forward迭代的情况下只能进行一次转换,但在使用std::size_t情况下,实际上在向后迭代的情况下可能会出错,例如std::size_tsize_type的typedef更宽):

使用std :: vector

使用迭代器

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

重要的是,总是对其定义不了解的迭代器使用前缀增量forms。 这将确保您的代码尽可能通用。

使用范围C ++ 11

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

使用索引

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

使用数组

使用迭代器

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

使用范围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方法可以产生的问题。

四年过去了, Google给了我这个答案。 使用标准的C ++ 11 (又名C ++ 0x ),实际上有一个新的令人愉快的方式(以打破向后兼容的价格):新的auto关键字。 它可以节省您不得不显式指定要使用的迭代器的types(再次重复向量types)的痛苦,当(编译器)显而易见的时候,使用哪种types。 用v作为你的vector ,你可以做这样的事情:

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

C ++ 11更进一步,为您提供了一个特殊的语法来迭代像vector集合。 它消除了写东西总是一样的必要性:

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

要在工作程序中看到它,build立一个文件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 ++编译器的,程序应该是平台(和编译器)独立的。

在你的例子中的具体情况,我会使用STLalgorithm来完成这个。

 #include <numeric> sum = std::accumulate( polygon.begin(), polygon.end(), 0 ); 

对于一个更一般的,但仍然相当简单的情况下,我会去:

 #include <boost/lambda/lambda.hpp> #include <boost/lambda/bind.hpp> using namespace boost::lambda; std::for_each( polygon.begin(), polygon.end(), sum += _1 ); 

关于Johannes Schaub的回答:

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

这可能适用于一些编译器,但不适用于gcc。 这里的问题是如果std :: vector :: iterator是一个types,一个variables(成员)或一个函数(方法)的问题。 我们用gcc得到以下错误:

 In member function 'void MyClass<T>::myMethod()': error: expected `;' before 'it' error: 'it' was not declared in this scope In member function 'void MyClass<T>::sort() [with T = MyClass]': instantiated from 'void MyClass<T>::run() [with T = MyClass]' instantiated from here dependent-name 'std::vector<T*,std::allocator<T*> >::iterator' is parsed as a non-type, but instantiation yields a type note: say 'typename std::vector<T*,std::allocator<T*> >::iterator' if a type is meant 

解决方法是使用关键字“typename”,如下所示:

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

vector<T>::size()的调用返回std::vector<T>::size_typetypes的值,而不是int,unsigned int或其他值。

另外,通常使用迭代器完成对C ++中的容器的迭代 ,就像这样。

 std::vector<T>::iterator i = polygon.begin(); std::vector<T>::iterator end = polygon.end(); for(; i != end; i++){ sum += *i; } 

其中T是您存储在向量中的数据types。

或者使用不同的迭代algorithm( std::transformstd::copystd::fillstd::for_each等等)。

使用size_t

 for (size_t i=0; i < polygon.size(); i++) 

引用维基百科 :

stdlib.h和stddef.h头文件定义了一个名为size_t的数据types,用于表示对象的大小。 需要大小的库函数期望它们是size_ttypes,并且sizeof运算符的计算结果是size_t

size_t的实际types是平台相关的; 一个常见的错误是假设size_t与unsigned int相同,这会导致编程错误,特别是在64位体系结构变得更普遍的情况下。

我通常使用BOOST_FOREACH:

 #include <boost/foreach.hpp> BOOST_FOREACH( vector_type::value_type& value, v ) { // do something with 'value' } 

它适用于STL容器,数组,C风格的string等。

为了完整,C ++ 11语法只为迭代器( ref )启用另一个版本:

 for(auto it=std::begin(polygon); it!=std::end(polygon); ++it) { // do something with *it } 

反向迭代也很舒服

 for(auto it=std::end(polygon)-1; it!=std::begin(polygon)-1; --it) { // do something with *it } 

在C ++ 11中

我会使用像for_each这样的通用algorithm来避免search正确types的迭代器和lambdaexpression式,以避免额外命名的函数/对象。

对于您的特定情况(假设多边形是整数向量)的简短“漂亮”示例:

 for_each(polygon.begin(), polygon.end(), [&sum](int i){ sum += i; }); 

testing: http : //ideone.com/i6Ethd

不要忘了包括:algorithm,当然,vector:)

微软实际上也有一个很好的例子:
来源: http : //msdn.microsoft.com/en-us/library/dd293608.aspx

 #include <algorithm> #include <iostream> #include <vector> using namespace std; int main() { // Create a vector object that contains 10 elements. vector<int> v; for (int i = 1; i < 10; ++i) { v.push_back(i); } // Count the number of even numbers in the vector by // using the for_each function and a lambda. int evenCount = 0; for_each(v.begin(), v.end(), [&evenCount] (int n) { cout << n; if (n % 2 == 0) { cout << " is even " << endl; ++evenCount; } else { cout << " is odd " << endl; } }); // Print the count of even numbers to the console. cout << "There are " << evenCount << " even numbers in the vector." << endl; } 
 for (vector<int>::iterator it = polygon.begin(); it != polygon.end(); it++) sum += *it; 

有点历史:

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

std::vector::size()返回一个unsigned ,为什么一个向量具有负的长度?

警告告诉你,不平等声明的正确操作数可以容纳更多的数据,然后左边。

基本上,如果你有一个向量超过20亿条目,并使用整数索引,你会遇到溢出问题(整数将回绕到负20亿)。

第一种是正确的,在某种严格意义上是正确的。 (如果你想的是,大小永远不能小于零)。但是,这个警告让我觉得被忽略的好select之一。

考虑你是否需要迭代

<algorithm>标准头为我们提供了这样的function:

 using std::begin; // allows argument-dependent lookup even using std::end; // if the container type is unknown here auto sum = std::accumulate(begin(polygon), end(polygon), 0); 

algorithm库中的其他function执行常见任务 – 确保知道可用的function是否可以节省您的工作量。