std::function 是可调用对象的类型擦除容器,非万能函数指针;支持函数指针、lambda、bind 等,但有开销、不可比较、移动后状态未定义。
直接说结论:std::function 不是“万能函数指针”,它本质是可调用对象的类型擦除容器,能存函数指针、lambda、绑定表达式、成员函数指针等,但有开销、不能比较相等、不支持移动后状态检查。
声明时必须显式指定签名,比如 std::function 表示接受两个 int 参数、返回 int 的可调用对象。常见错误是漏写括号或参数类型不匹配:
std::function f = [](int a, int b) { return a + b; }; —— 这行其实对,但若 lambda 捕获了局部变量而没加 [&] 或 [=],编译失败std::function f = some_function_ptr; 而 some_function_ptr 实际是 void(*)(int) —— 签名不兼容,直接编译报错普通函数指针、无捕获 lambda(自动转为函数指针)、std::bind 结果、std::mem_fn 或成员函数指针包装体
std::function 内部用小对象优化(SOO),通常前 16–32 字节存在自身对象里;一旦 lambda 捕获大量数据(如大数组、std::string、std::vector),就会触发堆分配。这不是 bug,但容易被忽略:
[x](int y){ return x + y; },其中 x 是 int)—— 通常不堆分配[data = std::vector(100000)](){ ... } )—— 必然堆分配,且拷贝构造 std::function 会复制整个 vector[&data](注意生命周期!),或把大数据抽成外部对象,只捕获指针/引用std::vectorbig_data(100000, 42); auto bad_lambda = [big_data]() { return big_data.size(); }; // 堆分配,拷贝重 auto good_lambda = [&big_data]() { return big_data.size(); }; // 不复制 data,但需确保 big_data 活得比 function 久 std::function f = good_lambda;
不能直接把成员函数指针赋给 std::function,因为缺少 this。必须绑定实例(或用 std::bind / lambda 包装):
立即学习“C++免费学习笔记(深入)”;
std::function f = &MyClass::do_something; —— 编译失败,“no known conversion”MyClass obj; std::function f = [&obj]() { obj.do_something(); };
std::function f = std::bind(&MyClass::do_something, &obj);
std::bind 绑定临时对象(如 std::bind(..., MyClass{})),调用时 this 悬空,UB如果函数调用在 hot path(如循环内、图形渲染每帧调用),std::function 的虚函数调用开销(即使 SOO)和可能的堆访问会影响性能。这时应考虑:
operator(),零开销,但失去类型擦除能力std::function —— 它的便利性是有代价的真正麻烦的不是怎么写,而是忘记它背后是类型擦除+运行时分发,以及移动后原对象进入有效但未指定状态(不能再次调用,也不能比较)。