简体   繁体   English

C ++ STL - 遍历序列中的所有内容

[英]C++ STL - iterate through everything in a sequence

I have a sequence, eg 我有一个序列,例如

std::vector< Foo > someVariable;

and I want a loop which iterates through everything in it. 我想要一个循环遍历其中的所有内容。

I could do this: 我能做到这一点:

for (int i=0;i<someVariable.size();i++) {
    blah(someVariable[i].x,someVariable[i].y);
    woop(someVariable[i].z);
}

or I could do this: 或者我可以这样做:

for (std::vector< Foo >::iterator i=someVariable.begin(); i!=someVariable.end(); i++) {
    blah(i->x,i->y);
    woop(i->z);
}

Both these seem to involve quite a bit of repetition / excessive typing. 这些似乎都涉及相当多的重复/过度打字。 In an ideal language I'd like to be able to do something like this: 在理想的语言中,我希望能够做到这样的事情:

for (i in someVariable) {
    blah(i->x,i->y);
    woop(i->z);
}

It seems like iterating through everything in a sequence would be an incredibly common operation. 似乎迭代顺序中的所有内容将是一个非常常见的操作。 Is there a way to do it in which the code isn't twice as long as it should have to be? 有没有办法做到这一点,代码不是它应该的两倍长?

You could use for_each from the standard library. 您可以使用标准库中的for_each You could pass a functor or a function to it. 您可以将仿函数或函数传递给它。 The solution I like is BOOST_FOREACH , which is just like foreach in other languages. 我喜欢的解决方案是BOOST_FOREACH ,就像其他语言中的foreach一样。 C+0x is gonna have one btw. C + 0x会有一个顺便说一句。

For example: 例如:

#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/foreach.hpp>

#define foreach BOOST_FOREACH 

void print(int v)
{
    std::cout << v << std::endl;
}

int main()
{
    std::vector<int> array;

    for(int i = 0; i < 100; ++i)
    {
        array.push_back(i);
    }

    std::for_each(array.begin(), array.end(), print); // using STL

    foreach(int v, array) // using Boost
    {
        std::cout << v << std::endl;
    }
}

Not counting BOOST_FOREACH which AraK already suggested, you have the following two options in C++ today: 不计算AraK已经建议的BOOST_FOREACH,你今天在C ++中有以下两个选项:

void function(Foo& arg){
  blah(arg.x, arg.y);
  woop(arg.z);
}

std::for_each(someVariable.begin(), someVariable.end(), function); 

struct functor {
  void operator()(Foo& arg){
    blah(arg.x, arg.y);
    woop(arg.z);
  }
};

std::for_each(someVariable.begin(), someVariable.end(), functor());

Both require you to specify the "body" of the loop elsewhere, either as a function or as a functor (a class which overloads operator() ). 两者都要求您在其他地方指定循环的“主体”,作为函数或函数(一个重载operator() )。 That might be a good thing (if you need to do the same thing in multiple loops, you only have to define the function once), but it can be a bit tedious too. 可能是一件好事(如果你需要在多个循环中做同样的事情,你只需要定义一次函数),但它也可能有点乏味。 The function version may be a bit less efficient, because the compiler is generally unable to inline the function call. 函数版本的效率可能稍低,因为编译器通常无法内联函数调用。 (A function pointer is passed as the third argument, and the compiler has to do some more detailed analysis to determine which function it points to) (函数指针作为第三个参数传递,编译器必须进行更详细的分析以确定它指向的函数)

The functor version is basically zero overhead. 仿函数版本基本上是零开销。 Because an object of type functor is passed to for_each , the compiler knows exactly which function to call: functor::operator() , and so it can be trivially inlined and will be just as efficient as your original loop. 因为functor类型的对象被传递给for_each ,所以编译器确切地知道调用哪个函数: functor::operator() ,因此它可以简单地内联并且与原始循环一样有效。

C++0x will introduce lambda expressions which make a third form possible. C ++ 0x将引入lambda表达式,使第三种形式成为可能。

std::for_each(someVariable.begin(), someVariable.end(), [](Foo& arg){
  blah(arg.x, arg.y);
  woop(arg.z);
});

Finally, it will also introduce a range-based for loop: 最后,它还将介绍一个基于范围的for循环:

for(Foo& arg : my_someVariable)
{
  blah(arg.x, arg.y);
  woop(arg.z);
}

So if you've got access to a compiler which supports subsets of C++0x, you might be able to use one or both of the last forms. 因此,如果您可以访问支持C ++ 0x子集的编译器,那么您可以使用最后一个或两个表单。 Otherwise, the idiomatic solution (without using Boost) is to use for_each like in one of the two first examples. 否则,惯用解决方案(不使用Boost)就像在前两个示例中的一个中一样使用for_each

Prefer algorithm calls to hand-written loops 首选算法调用手写循环

There are three reasons: 原因有三:

1) Efficiency: Algorithms are often more efficient than the loops programmers produce 1) 效率:算法通常比程序员生成的循环更有效

2) Correctness: Writing loops is more subject to errors than is calling algorithms. 2) 正确性:写入循环比调用算法更容易出错。

3) Maintainability: Algorithm calls often yield code that is clearer and more 3) 可维护性:算法调用通常产生更清晰和更多的代码
straightforward than the corresponding explicit loops. 比相应的显式循环简单明了。

By the way, MSVS 2008 has a "for each" C++ keyword. 顺便说一下,MSVS 2008有一个“for each”C ++关键字。 Look at How to: Iterate Over STL Collection with for each . 看看如何:迭代STL集合

int main() {
   int retval = 0;

   vector<int> col(3);
   col[0] = 10;
   col[1] = 20;
   col[2] = 30;

   for each( const int& c in col )
      retval += c;

   cout << "retval: " << retval << endl;
}

Prefer almost every other algorithm to for_each() 几乎所有其他算法都优先于for_each()

There are two reasons: 有两个原因:

  1. for_each is extremely general, telling you nothing about what's really being done, just that you're doing something to all the items in a sequence. for_each是非常通用的,不会告诉你什么是真正做的,只是你正在对序列中的所有项目做些什么。
  2. A more specialized algorithm will often be simpler and more direct 更专业的算法通常更简单,更直接

Consider, an example from an earlier reply: 考虑一下先前回复中的一个例子:

void print(int v)
{
    std::cout << v << std::endl;
}
// ...
std::for_each(array.begin(), array.end(), print); // using STL

Using std::copy instead, that whole thing turns into: 使用std :: copy代替,整个事情变成:

std::copy(array.begin(), array.end(), std::ostream_iterator(std::cout, "\\n")); std :: copy(array.begin(),array.end(),std :: ostream_iterator(std :: cout,“\\ n”));

"struct functor {
  void operator()(Foo& arg){
    blah(arg.x, arg.y);
    woop(arg.z);
  }
};

std::for_each(someVariable.begin(), someVariable.end(), functor());"

I think approaches like these are often needlessly baroque for a simple problem. 我认为像这样的方法通常是不必要的巴洛克式的简单问题。

do i=1,N
 call blah( X(i),Y(i) )
 call woop( Z(i) )
end do

is perfectly clear, even if it's 40 years old (and not C++, obviously). 非常清楚,即使它已经40岁了(显然不是C ++)。

If the container is always a vector (STL name), I see nothing wrong with an index and nothing wrong with calling that index an integer. 如果容器总是一个向量(STL名称),我看到索引没有错,并且将该索引称为整数并没有错。

In practice, often one needs to iterate over multiple containers of the same size simultaneously and peel off a datum from each, and do something with the lot of them. 在实践中,通常需要同时迭代多个相同大小的容器并从每个容器中剥离一个数据,并对其中的许多进行处理。 In that situation, especially, why not use the index? 在那种情况下,尤其是为什么不使用索引?

As far as SSS's points #2 and #3 above, I'd say it could be so for complex cases, but often iterating 1...N is often as simple and clear as anything else. 就SSS的第2点和第3点而言,我认为对于复杂的情况可能会如此,但经常迭代1 ... N通常与其他任何事情一样简单明了。

If you had to explain the algorithm on the whiteboard, could you do it faster with, or without, using 'i'? 如果你必须在白板上解释算法,你可以使用或不使用'i'来更快地完成它吗? I think if your meatspace explanation is clearer with the index, use it in codespace. 我想如果您的meatspace解释更清楚,请在代码空间中使用它。

Save the heavy C++ firepower for the hard targets. 为强硬目标保存沉重的C ++火力。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM