C++ 迭代 std::vector:无符号与有符号索引变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/409348/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 15:11:52  来源:igfitidea点击:

Iteration over std::vector: unsigned vs signed index variable

c++stlunsignedsigned

提问by Yuval Adam

What is the correct way of iterating over a vector in C++?

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

Consider these two code fragments, this one works fine:

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

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

and this one:

和这个:

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

which generates warning: comparison between signed and unsigned integer expressions.

生成warning: comparison between signed and unsigned integer expressions.

I'm new in the world of C++, so the unsignedvariable looks a bit frightening to me and I know unsignedvariables can be dangerous if not used correctly, so - is this correct?

我是 C++ 世界的新手,所以这个unsigned变量对我来说看起来有点吓人,我知道unsigned如果使用不当,变量可能会很危险,所以 - 这是正确的吗?

回答by Johannes Schaub - litb

For iterating backwards see this answer.

要向后迭代,请参阅此答案

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_tas the index variable type. However, that is not portable. Always use the size_typetypedef 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_tis wider than what is the typedef of size_type):

向前迭代几乎相同。只需按增量更改迭代器/交换递减。你应该更喜欢迭代器。有人告诉你使用std::size_t作为索引的变量类型。但是,这不是便携式的。始终使用size_type容器的typedef(虽然在前向迭代情况下您可以只进行转换,但在使用时在向后迭代情况下实际上可能一直出错std::size_t,以防std::size_t比 的 typedef 更宽size_type) :



Using std::vector

使用 std::vector

Using iterators

使用迭代器

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

Important is, always use the prefix increment form for iterators whose definitions you don't know. That will ensure your code runs as generic as possible.

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

Using Range C++11

使用范围 C++11

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

Using indices

使用索引

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


Using arrays

使用数组

Using iterators

使用迭代器

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

Using Range C++11

使用范围 C++11

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

Using indices

使用索引

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

Read in the backward iterating answer what problem the sizeofapproach can yield to, though.

不过,请阅读向后迭代的答案,该sizeof方法可以解决什么问题。

回答by kratenko

Four years passed, Googlegave me this answer. With the standard C++11(aka C++0x) there is actually a new pleasant way of doing this (at the price of breaking backward compatibility): the new autokeyword. It saves you the pain of having to explicitly specify the type of the iterator to use (repeating the vector type again), when it is obvious (to the compiler), which type to use. With vbeing your vector, you can do something like this:

四年过去了,谷歌给了我这个答案。对于标准的C++11(又名C++0x),实际上有一种新的令人愉快的方式(以破坏向后兼容性为代价):newauto关键字。当(对编译器)使用哪种类型很明显时,它可以避免必须显式指定要使用的迭代器类型(再次重复向量类型)的痛苦。随着v做你的vector,你可以这样做:

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

C++11goes even further and gives you a special syntax for iterating over collections like vectors. It removes the necessity of writing things that are always the same:

C++11走得更远,为您提供了一种特殊的语法来迭代向量等集合。它消除了编写始终相同的东西的必要性:

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

To see it in a working program, build a file auto.cpp:

要在工作程序中查看它,请构建一个文件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;
}

As of writing this, when you compile this with g++, you normally need to set it to work with the new standard by giving an extra flag:

在写这篇文章时,当你用g++编译它时,你通常需要通过提供一个额外的标志来设置它以使用新标准:

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

Now you can run the example:

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

$ ./auto
17
12
23
42

Please notethat the instructions on compiling and running are specific to gnu c++compiler on Linux, the program should be platform (and compiler) independent.

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

回答by paxos1977

In the specific case in your example, I'd use the STL algorithms to accomplish this.

在您的示例中的特定情况下,我将使用 STL 算法来完成此操作。

#include <numeric> 

sum = std::accumulate( polygon.begin(), polygon.end(), 0 );

For a more general, but still fairly simple case, I'd go with:

对于更一般但仍然相当简单的情况,我会选择:

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

using namespace boost::lambda;
std::for_each( polygon.begin(), polygon.end(), sum += _1 );

回答by Polat Tuzla

Regarding Johannes Schaub's answer:

关于 Johannes Schaub 的回答:

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

That may work with some compilers but not with gcc. The problem here is the question if std::vector::iterator is a type, a variable (member) or a function (method). We get the following error with gcc:

这可能适用于某些编译器,但不适用于 gcc。这里的问题是 std::vector::iterator 是类型、变量(成员)还是函数(方法)的问题。我们使用 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

The solution is using the keyword 'typename' as told:

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

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

回答by Jasper Bekkers

A call to vector<T>::size()returns a value of type std::vector<T>::size_type, not int, unsigned int or otherwise.

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

Also generally iteration over a container in C++ is done using iterators, like this.

通常,在 C++ 中对容器的迭代也是使用iterators完成的,就像这样。

std::vector<T>::iterator i = polygon.begin();
std::vector<T>::iterator end = polygon.end();

for(; i != end; i++){
    sum += *i;
}

Where T is the type of data you store in the vector.

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

Or using the different iteration algorithms (std::transform, std::copy, std::fill, std::for_eachet cetera).

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

回答by Igor Oks

Use size_t:

使用size_t

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

Quoting Wikipedia:

引用维基百科

The stdlib.h and stddef.h header files define a datatype called size_twhich is used to represent the size of an object. Library functions that take sizes expect them to be of type size_t, and the sizeof operator evaluates to size_t.

The actual type of size_tis platform-dependent; a common mistake is to assume size_tis the same as unsigned int, which can lead to programming errors, particularly as 64-bit architectures become more prevalent.

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

的实际类型size_t是平台相关的;一个常见的错误是假设size_t与 unsigned int 相同,这会导致编程错误,尤其是在 64 位体系结构变得更加普遍时。

回答by ecoffey

A bit of history:

一点历史:

To represent whether a number is negative or not computer use a 'sign' bit. intis a signed data type meaning it can hold positive and negative values (about -2billion to 2billion). Unsignedcan only store positive numbers (and since it doesn't waste a bit on metadata it can store more: 0 to about 4billion).

要表示数字是否为负数,计算机使用“符号”位。 int是一种有符号数据类型,这意味着它可以包含正值和负值(大约 -20 亿到 20 亿)。 Unsigned只能存储正数(并且因为它不会在元数据上浪费一点,所以它可以存储更多:0 到大约 40 亿)。

std::vector::size()returns an unsigned, for how could a vector have negative length?

std::vector::size()返回 an unsigned,因为向量如何具有负长度?

The warning is telling you that the right operand of your inequality statement can hold more data then the left.

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

Essentially if you have a vector with more then 2 billion entries and you use an integer to index into you'll hit overflow problems (the int will wrap back around to negative 2 billion).

基本上,如果您有一个包含超过 20 亿个条目的向量,并且您使用一个整数来索引,您将遇到溢出问题(int 将返回到负 20 亿)。

回答by Martin Cote

I usually use BOOST_FOREACH:

我通常使用 BOOST_FOREACH:

#include <boost/foreach.hpp>

BOOST_FOREACH( vector_type::value_type& value, v ) {
    // do something with 'value'
}

It works on STL containers, arrays, C-style strings, etc.

它适用于 STL 容器、数组、C 样式字符串等。

回答by Jan Turoň

To be complete, C++11 syntax enables just one another version for iterators (ref):

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

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

Which is also comfortable for reverse iteration

这对于反向迭代也很舒服

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

回答by jave.web

In C++11

在 C++11 中

I would use general algorithms like for_eachto avoid searching for the right type of iterator and lambda expression to avoid extra named functions/objects.

我会使用通用算法for_each来避免搜索正确类型的迭代器和 lambda 表达式以避免额外的命名函数/对象。

The short "pretty" example for your particular case (assuming polygon is a vector of integers):

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

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

tested on: http://ideone.com/i6Ethd

测试:http: //ideone.com/i6Ethd

Dont' forget to include:algorithm and, of course, vector :)

不要忘记包括:算法,当然还有向量:)

Microsoft has actually also a nice example on this:
source: http://msdn.microsoft.com/en-us/library/dd293608.aspx

微软实际上也有一个很好的例子:
来源: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;
}