代码之家  ›  专栏  ›  技术社区  ›  Egon Alon Lavian

了解stl中的函数

  •  2
  • Egon Alon Lavian  · 技术社区  · 15 年前

    NM JouthTIS第5.9节从“C++标准库”引证


    #include < iostream>
    #include < list>
    #include < algorithm>
    
    using namespace std;
    
    //function object that adds the value with which it is initialized
    class AddValue {
        private:
           int the Value; //the value to add
        public:
           //constructor initializes the value to add
           AddValue(int v) : theValue(v) {    }
           //the "function call" for the element adds the value
           void operator() (int& elem) const {  elem += theValue; }
     };
    
    int main()
    {
          list<int> coll;
          for (int i=1; i<=9; ++i) 
             coll.push_back(i); 
    
          //The first call of for_each() adds 10 to each value:
          for_each (coll.begin(), coll.end(), AddValue(10)) ; 
    

    在这里,表达式addvalue(10)创建一个addvalue类型的对象,该对象由 值10。The constructor of AddValue stores this value as the member theValue. 里面 for_each(), "()" is called for each element of coll. Again, this is a call of operator () for 传递的AddValue类型的临时函数对象。实际元素作为 争论。函数对象将其值10添加到每个元素中。然后元素有 以下值: after adding 10:

    11 12 13 14 15 16 17 18 19
    

    The second call of for_each() uses the same functionality to add the value of the first element 每个元素。它用第一个元素初始化addValue类型的临时函数对象 收藏集:

    for_each (coll.begin(), coll.end(), AddValue (*coll. begin()) ) ; 
    

    添加第一个元素后,输出如下:

    22 23 24 25 26 27 28 29 30
    

    我不理解的是第二种情况为什么输出不是

    22 34 35 36 37 38 39 40 41
    

    meaning is a new functor being created for each call or is the functor used for each call ?

    6 回复  |  直到 13 年前
        1
  •  6
  •   SCFrench    15 年前

    表达式 AddValue(*coll. begin()) creates one temporary object of class AddValue . That temporary is then passed to the for_each 功能。 每一个 then calls the object's function call operator - that is, operator() - once for each element from coll.begin() coll.end() .

    技术上, 每一个 takes the functor parameter by value (not reference), so a it actually operates on a 复制 of the temporary, not the temporary itself.

        2
  •  1
  •   stinky472    15 年前

    [Edit] I originally misunderstood the author's original intent. I corrected the mistake.

    for_each (coll.begin(), coll.end(), AddValue (*coll. 开始());

    The output is then as follows after adding first element:

    22 23 24 25 26 27 28 29 30

    what I don't understand is in the second case why is the output is not

    22 34 35 36 37 38 39 40 41

    meaning is a new functor being created for each call or is the functor used 每次通话?

    First of all, regardless of whether the for_each algorithm copies the functor you pass in is irrelevant. What's relevant is that you should be storing the iterator or pointer to the first element rather than the pointee. If you do that and dereference it each time, it should do the trick.

    struct AddValue 
    {
        const int* ptr;
        explicit AddValue(const int* iptr): ptr(iptr) {}
        void operator() (int& elem) const {elem += *ptr; }
    };
    
    int main()
    {
        vector<int> v;
        for (int j=1; j <= 9; ++j)
            v.push_back(j + 10);
        for_each(v.begin(), v.end(), AddValue(&v[0]) );
        // v will be [22 34 35 36 37 38 39 40 41]
    }
    

    然而,我将不得不放弃我对函数编程的两点看法。通过函数编程,您可以得到非常简洁、精巧的代码。然而,调试也是一个很大的痛苦,它具有分散代码的效果。除非你的代码能从中受益匪浅,否则你可以考虑简单的基于迭代器的循环,因为这会让你的程序员更容易调试和阅读代码。

    过去我犯了一个错误,就是函数式编程过于繁琐,这让我的团队讨厌我。我痴迷于用组合谓词逻辑编写非常严格的代码,并构建了大量的函数对象库,这些函数对象可以反复使用,也可以组合使用。实际上,我所做的是花费大量的时间来编写函子,那时我本来可以编写简单的、同样可重用的函数,而不是从简单的基于迭代器的循环(更容易用C++0x的基于循环的范围和BooStYfFux编写)来调用(并且内联同样容易)。我仍然在C++中使用函数式编程,但要节俭。当你经历了很多困难,并且不断积累时间,将两三行代码组合成一行代码时,你真的需要问问自己,并深入思考它是否值得,不仅是对你自己,而且对每一个使用代码的人来说。

        3
  •  0
  •   user283145    15 年前

    Yes, it is what you said. Functors are passed by value by default and thus they are copied in code of std::for_each. However you could write your own version of std::for_each explicitly stating that you want to pass functor by reference.

        4
  •  0
  •   Edward Strange    15 年前

    对。将为每个函数传递一个新的函数副本allong。你正在读的书解释了这一点。

        5
  •  0
  •   Stack Overflow is garbage    15 年前

    I believe the reason why the functor is copied around like this is to make for_each 更一般。

    设想一个引用该函数的实现。如果该函数是一个右值(例如,如果它是从另一个函数返回的),则会中断:

    std::for_each(first, last, get_functor(...))
    

    唯一真正的通用解决方案是通过值传递函子。然后用const、非const、rValm和LValm函子进行运算。

        6
  •  0
  •   CB Bailey    15 年前

    你的 AddValue constructor takes an int so when you construct it from *coll.begin() then value of the first member of your collection is used to initialize the member variable theValue .

    This is now fixed (nothing else modifies 价值 所以每次 价值 从这个开始使用 附加值 object or any copies of this 附加值 object it will still have the same value with which it was initialized.

    这就是 *开始() 在第一次 附加值 object was constructed, not the value *开始() might have been modified to.