一、std::function 是怎么存任意可调用对象的?
std::function<int(int, int)> f = [](int a, int b) { return a + b; };
int result = f(3, 4); // 7
你传进去的是一个 lambda(每 lambda 类型不同),但 f 能统一调用。这靠的就是 Type Erasure。
二、小对象优化(SBO)
std::function 内部有一个小缓冲区(通常是 16-32 字节):
如果可调用对象 ≤ SBO 阈值:
┌─────────────────────────────────┐
│ vptr │ 小缓冲区(存 lambda) │ ← 栈上,无堆分配
└─────────────────────────────────┘
如果可调用对象 > SBO 阈值:
┌─────────────────────────────────┐
│ vptr │ ptr → 堆上的 lambda │ ← 一次堆分配
└─────────────────────────────────┘
实测:
// 小 lambda(捕获 2 个 int,16 字节)→ SBO,无堆分配
int a = 1, b = 2;
auto small = [a, b](int x) { return a + b + x; };
// 大 lambda(捕获一个大 vector)→ 堆分配
vector<int> v(1000);
auto big = [v](int x) { return v.size() + x; };
面试题:“为什么高频构造 std::function 性能差?”
- 大捕获对象触发堆分配。
- Type Erasure 虚函数调用。
std::function的拷贝赋值运算符有引用计数的原子操作。