zoukankan      html  css  js  c++  java
  • c++ 11学习笔记--Lambda 表达式(对比测试Lambda ,bind,Function Object)

    所有c++ coder都应该为这个语法感到高兴,说的直白一点,Lambda 表达式就是函数对象的语法糖。

    还是直接看对比栗子吧,抄袭的是msdn的官网

    该示例使用 for_each 函数调用中嵌入的 lambda 向控制台打印 vector 对象中的每个元素是偶数还是奇数。

    使用lambda

    #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 = 0; 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;
    }

    使用Function Object

    #include <algorithm>
    #include <iostream>
    #include <vector>
    using namespace std;
    
    class FunctorClass
    {
    public:
        // The required constructor for this example.
        explicit FunctorClass(int& evenCount) 
            : m_evenCount(evenCount)
        {
        }
    
        // The function-call operator prints whether the number is
        // even or odd. If the number is even, this method updates
        // the counter.
        void operator()(int n) const
        {
            cout << n;
    
            if (n % 2 == 0) {
                cout << " is even " << endl;
                ++m_evenCount;
            } else {
                cout << " is odd " << endl;
            }
        }
    
    private:
        // Default assignment operator to silence warning C4512.
        FunctorClass& operator=(const FunctorClass&);
    
        int& m_evenCount; // the number of even variables in the vector.
    };
    
    
    int main() 
    {
        // Create a vector object that contains 10 elements.
        vector<int> v;
        for (int i = 0; i < 10; ++i) {
            v.push_back(i);
        }
    
        // Count the number of even numbers in the vector by 
        // using the for_each function and a function object.
        int evenCount = 0;
        for_each(v.begin(), v.end(), FunctorClass(evenCount));
    
        // Print the count of even numbers to the console.
        cout << "There are " << evenCount 
            << " even numbers in the vector." << endl;
    }

    正如微软文档所言,这两种在效率上并没有实质性的差距,我自己也测试了,不管在debug模式下还是release模式下,果然没有差距。

    无意中我在晚上发现了bind和Lambda对比测试,前三种方式是网上的,后面两种是我自己加的,结果绝对让我蛋碎了一地。

    #include <cstdint>
    #include <chrono>
    #include <iostream>
    #include <string>
    #include <thread>
    #include <vector>
    #include <algorithm>
    
    #if USE_BOOST
    #include <boost/function.hpp>
    #include <boost/bind.hpp>
    #endif
    
    
    class FunctorClass
    {
    public:
        // The required constructor for this example.
        explicit FunctorClass(uint64_t& evenCount)
        : m_evenCount(evenCount)
        {
        }
        
        // The function-call operator prints whether the number is
        // even or odd. If the number is even, this method updates
        // the counter.
        void operator()(int n) const
        {
             m_evenCount += n;
        }
        
    private:
        // Default assignment operator to silence warning C4512.
        FunctorClass& operator=(const FunctorClass&);
        
        uint64_t& m_evenCount; // the number of even variables in the vector.
    };
    
    class timer
    {
    public:
        typedef std::chrono::high_resolution_clock clock;
        typedef clock::time_point                  time_point;
        typedef clock::duration                    duration;
        
    public:
        timer()
        {
            reset();
        }
        
        void reset()
        {
            _starttime = clock::now();
        }
        
        duration elapsed() const
        {
            return clock::now() - _starttime;
        }
    protected:
        time_point _starttime;
    };
    
    bool test_timer()
    {
        using std::chrono::milliseconds;
        typedef timer::duration duration;
        
        const milliseconds sleep_time(500);
        
        timer t;
        std::this_thread::sleep_for(sleep_time);
        duration recorded = t.elapsed();
        
        // make sure the clock and this_thread::sleep_for is precise within one millisecond (or at least in agreement as to
        // how inaccurate they are)
        return (recorded - milliseconds(1) < sleep_time)
        && (recorded + milliseconds(1) > sleep_time);
    }
    
    template <typename T>
    void volatile_write(const T& x)
    {
        volatile T* p = new T;
        *p = x;
        delete p;
    }
    
    template <typename Function>
    void run_test(const std::string& name, Function func)
    {
        std::cout << name;
        timer t;
        volatile_write(func());
        timer::duration duration = t.elapsed();
        std::cout << '	' << duration.count() << std::endl;
    }
    
    template <typename Function>
    void do_test_loop(Function func, const uint64_t upper_limit = 100000000ULL)
    {
        uint64_t i;
        for (i = 0; i < upper_limit; ++i)
            func(i);
        if(i == upper_limit)
        {
            std::cout<<i;
        }
    }
    
    uint64_t test_accumulate_lambda()
    {
        uint64_t x = 0;
        auto accumulator = [&x] (uint64_t i) { x += i;
     };
        do_test_loop(accumulator);
        return x;
    }
    
    void test_accumulate_bind_function(uint64_t& x, uint64_t i)
    {
        x += i;
    }
    
    uint64_t test_accumulate_bind()
    {
        namespace arg = std::placeholders;
        
        uint64_t x = 0;
        std::function<void (uint64_t)> accumulator = std::bind(&test_accumulate_bind_function, std::ref(x), arg::_1);
        do_test_loop(accumulator);
        return x;
    }
    
    uint64_t test_accumulate_bound_lambda()
    {
        uint64_t x = 0;
        std::function<void (uint64_t)> accumulator = [&x] (uint64_t i) { x += i; };
        do_test_loop(accumulator);
        return x;
    }
    
    
    uint64_t test_accumulate_class_function()
    {
        uint64_t x = 0;
    
        do_test_loop(FunctorClass(x));
       // for_each(v.begin(), v.end(), FunctorClass(x));
        return x;
    }
    
    uint64_t test_accumulate_bind_auto()
    {
        namespace arg = std::placeholders;
        
        uint64_t x = 0;
        auto accumulator = std::bind(&test_accumulate_bind_function, std::ref(x), arg::_1);
        do_test_loop(accumulator);
        return x;
    }
    
    #if USE_BOOST
    uint64_t test_accumulate_boost_bind()
    {
        uint64_t x = 0;
        
        boost::function<void (uint64_t)> accumulator = boost::bind(&test_accumulate_bind_function, boost::ref(x), _1);
        do_test_loop(accumulator);
        return x;
    }
    
    uint64_t test_accumulate_boost_bound_lambda()
    {
        uint64_t x = 0;
        boost::function<void (uint64_t)> accumulator = [&x] (uint64_t i) { x += i; };
        do_test_loop(accumulator);
        return x;
    }
    #endif
    
    int main()
    {
        if (!test_timer())
        {
            std::cout << "Failed timer test." << std::endl;
            return -1;
        }
        
        run_test("Accumulate (lambda)            ", &test_accumulate_lambda);
        run_test("Accumulate (bind)              ", &test_accumulate_bind);
        run_test("Accumulate (bound lambda)      ", &test_accumulate_bound_lambda);
        run_test("Accumulate (Function Object)    ", &test_accumulate_class_function);
        run_test("Accumulate (bind auto)    ", &test_accumulate_bind_auto);
    #if USE_BOOST
        run_test("Accumulate (boost bind)        ", &test_accumulate_boost_bind);
        run_test("Accumulate (boost bound lambda)", &test_accumulate_bound_lambda);
    #endif
    }

    debug模式:

    Accumulate (lambda)            100000000  422885105

    Accumulate (bind)              100000000   4346676523

    Accumulate (bound lambda)      100000000 1707092933

    Accumulate (class function)    100000000   494674507

    Accumulate (bind auto)         100000000 3381097610

     

    Release模式

    Accumulate (lambda)            100000000  17978

    Accumulate (bind)              100000000   607188485

    Accumulate (bound lambda)      100000000 520421500

    Accumulate (Function Object)    100000000  1925

    Accumulate (bind auto)         100000000 1726

    编译器:APPLE LLVM5.1

    c++就是这样让人蛋疼,随便一个东西,初学者都可以写5中写法,那大神下,至少可以写10种以上,效率上的差距也是大的惊人,我还是那句话c++应该做减法了。

  • 相关阅读:
    冲刺计划安排
    团队作业7——Alpha冲刺之事后诸葛亮
    团队作业6--展示博客(Alpha版本)
    团队作业5——测试与发布(Alpha版本)
    团队项目汇总
    【Java】五种常见排序之------------------快速排序
    【Java】五种常见排序之----------------归并排序
    【Java】五种常见排序之----------------------插入排序
    【Java】五种常见排序之---------选择排序
    【Java】五种常见排序之-----------冒泡排序
  • 原文地址:https://www.cnblogs.com/budaixi/p/3874011.html
Copyright © 2011-2022 走看看