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 << '\t' << 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