迭代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 ++世界中的新成员,所以unsigned
variables对我来说看起来有些可怕,而且我知道,如果使用不正确, unsigned
variables可能是危险的,所以 – 这是正确的吗?
向后迭代
看到这个答案 。
迭代前锋
这几乎是相同的。 只需按增量更改迭代器/交换减量。 你应该更喜欢迭代器。 有些人告诉你使用std::size_t
作为索引variablestypes。 但是,这不是便携式的。 总是使用容器的size_type
typedef(虽然在forward迭代的情况下只能进行一次转换,但在使用std::size_t
情况下,实际上在向后迭代的情况下可能会出错,例如std::size_t
比size_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_type
types的值,而不是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::transform
, std::copy
, std::fill
, std::for_each
等等)。
使用size_t
:
for (size_t i=0; i < polygon.size(); i++)
引用维基百科 :
stdlib.h和stddef.h头文件定义了一个名为
size_t
的数据types,用于表示对象的大小。 需要大小的库函数期望它们是size_t
types,并且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是否可以节省您的工作量。