代码之家  ›  专栏  ›  技术社区  ›  Angus

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

  •  5
  • Angus  · 技术社区  · 16 年前

    std::vector< Foo > someVariable;
    

    我想要一个循环,循环遍历其中的所有内容。

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

    或者我可以这样做:

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

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

    在一个序列中遍历所有内容似乎是一个非常常见的操作。有没有一种方法可以使代码的长度不超过应该的两倍?

    6 回复  |  直到 16 年前
        1
  •  12
  •   Khaled Alshaya    16 年前

    你可以用 for_each 来自标准库。你可以传递一个函子或一个函数给它。我喜欢的解决办法是 BOOST_FOREACH ,这就像 foreach 用其他语言。C+0x将有一个btw。

    例如:

    #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;
        }
    }
    
        2
  •  5
  •   Stack Overflow is garbage    16 年前

    不算ARARK已经提出的BooStY-Frutax,你今天在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());
    

    两者都要求您在别处指定循环的“体”,要么作为函数,要么作为函子(重载的类) operator() 这是一件好事(如果您需要在多个循环中执行相同的操作,那么只需定义一次函数),但也可能有点乏味。函数版本可能效率稍低,因为编译器通常无法内联函数调用。(函数指针作为第三个参数传递,编译器必须进行更详细的分析以确定它指向哪个函数)

    函子版本的开销基本为零。因为一个类型为 functor for_each functor::operator() ,因此它可以简单地内联,并且与原始循环一样高效。

    C++0x将引入lambda表达式,使第三种形式成为可能。

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

    最后,它还将引入基于范围的for循环:

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

    因此,如果您有权访问支持C++0x子集的编译器,则可以使用最后的一种或两种形式。否则,惯用的解决方案(不使用Boost)是使用 就像前两个例子中的一个。

        3
  •  1
  •   Sergey Podobry    16 年前

    顺便说一下,MSVS 2008有一个“为每个”C++关键字。看看 How to: Iterate Over STL Collection with for each

    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;
    }
    
        4
  •  1
  •   Satbir    16 年前

    与手写循环相比,更喜欢算法调用

    原因有三:

    1) 算法通常比程序员产生的循环更有效

    2) 正确性: 编写循环比调用算法更容易出错。

    3) 可维护性: 算法调用通常会生成更清晰、更精确的代码

        5
  •  0
  •   Jerry Coffin    16 年前

    与for_each()相比,更喜欢几乎所有其他算法

    1. 因为每个都是非常一般的,没有告诉你真正在做什么,只是你在对序列中的所有项目做一些事情。
    2. 更专业的算法通常更简单、更直接

    考虑一下,一个较早回答的例子:

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

    使用std::copy,整个过程会变成:

    std::copy(array.begin()、array.end()、std::ostream_迭代器(std::cout,“\n”);

        6
  •  0
  •   Matt Kennel    16 年前
    "struct functor {
      void operator()(Foo& arg){
        blah(arg.x, arg.y);
        woop(arg.z);
      }
    };
    
    std::for_each(someVariable.begin(), someVariable.end(), functor());"
    

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

    完全清楚,即使它是40岁(显然不是C++)。

    如果容器始终是一个向量(STL名称),我认为索引没有错,将该索引称为整数也没有错。

    在实践中,通常需要同时迭代多个相同大小的容器,从每个容器中剥离一个数据,并对其中的许多容器进行处理。尤其是在这种情况下,为什么不使用索引呢?

    至于上面SSS的第2点和第3点,我认为对于复杂的情况也是如此,但通常迭代1…N通常和其他任何事情一样简单和清晰。

    如果你必须在白板上解释算法,你能用“i”或不用“i”更快吗?我认为,如果您的meatspace解释在索引中更清晰,请在代码空间中使用它。