Last updated:2026-10-12
C++ std::bind vs lambda¶
Interviews often ask: both std::bind and lambda can package a function plus its arguments into a callable object — which one should you use? Everyone can recite the answer, "use lambda", but why? Beyond readability, how big is the performance difference really? Talk is cheap, so I wrote a benchmark and measured it.
(1) Test subject: the same member function Calculator::calculate, packaged with std::bind and with a lambda respectively, then passed to the same template function f and called repeatedly;
(2) For fairness, f receives the callable as a template parameter (so the type-erasure overhead of std::function does not pollute the conclusion);
(3) Code and results: https://quick-bench.com/q/CEnR_XUuIwnZxaP4KJNSlpYG38c
#include <functional>
#include <numeric>
#include <vector>
struct Calculator {
int count{1};
int total{0};
auto calculate() -> void {
using std::iota, std::vector;
// Random math
vector<int> u(8), v(Calculator::count * u.size());
iota(v.begin(), v.end(), *u.begin());
int sum{*v.begin() + *u.begin()};
for (size_t pos{0}; pos < v.size(); ++pos) {
sum += u[pos % u.size()] * v[pos];
}
Calculator::total += sum;
++Calculator::count;
}
};
// auto f(std::function<void(int)> g) -> void { g(rand()); }
template<typename FN> auto f(FN g) -> void { g(rand()); }
static auto BM_bind(benchmark::State& state) -> void {
Calculator calculator;
for (auto _ : state) {
f(std::bind(&Calculator::calculate, &calculator));
}
}
static auto BM_lambda(benchmark::State& state) -> void {
Calculator calculator;
for (auto _ : state) {
f([&calculator]([[maybe_unused]] int x) { calculator.calculate(); });
}
}
BENCHMARK(BM_bind);
BENCHMARK(BM_lambda);
How to Read the Results¶
The lambda version comes out clearly faster than the bind version, for two main reasons:
(1) The binder type returned by std::bind stores "the bound callable + every placeholder argument" as members; a call has to go through a long chain of forwarding inside the standard library, and in early implementations bind objects had heavy copy semantics and were hard to inline. A lambda is just a closure object: it stores exactly what it captures, and the compiler inlines it without any obstacle.
(2) A subtler point: std::bind differs from lambda in how it handles argument evaluation order, overload resolution, and default arguments, and in C++11 times implementations even disagreed (the standard later tightened the behavior). Effective Modern C++ Item 34 has the full summary: prefer lambda over bind whenever you can.
The only remaining real use case for bind is basically this: before C++14 there were no generic lambdas and no init-capture, and std::bind's placeholders could do "argument reordering / partially pre-binding arguments". Today lambda can do all of that, and more intuitively.
A question to leave: change f above from a template to taking a std::function<void(int)> — how would the gap between the two benchmarks change, and why?
Related Topics¶
- How C++ std::move Works and How to Use It | C++那些事
- C++11 New Features Overview | C++那些事
- C++ Variadic Templates | C++那些事