std::function通过类型擦除统一处理各类可调用对象,解决了函数指针无法携带状态、成员函数回调复杂、Lambda类型不统一等问题,实现类型安全的通用回调,但需注意空调用、生命周期和性能开销等陷阱。

std::function
使用
std::function
std::function
#include <iostream>
#include <functional> // 引入 std::function
#include <string>
// 1. 普通自由函数
void greet(const std::string& name) {
std::cout << "Hello, " << name << "!" << std::endl;
}
// 2. 带有状态的函数对象 (Functor)
struct MyFunctor {
std::string prefix;
MyFunctor(const std::string& p) : prefix(p) {}
void operator()(const std::string& name) const {
std::cout << prefix << ", " << name << "!" << std::endl;
}
};
// 3. 带有成员函数的类
class EventProcessor {
public:
void process(const std::string& data) {
std::cout << "Processing data: " << data << std::endl;
}
};
// 示例函数,接受一个通用回调
void executeCallback(std::function<void(const std::string&)> callback, const std::string& arg) {
if (callback) { // 检查回调是否有效
callback(arg);
} else {
std::cout << "Callback is empty!" << std::endl;
}
}
int main() {
// 使用 std::function 存储和调用不同类型的可调用对象
// A. 存储一个普通函数
std::function<void(const std::string&)> callback1 = greet;
executeCallback(callback1, "Alice"); // 输出: Hello, Alice!
// B. 存储一个 Lambda 表达式
// Lambda 可以捕获外部变量,这里捕获了一个前缀
std::string customPrefix = "Greetings from Lambda";
auto lambdaCallback = [&](const std::string& name) {
std::cout << customPrefix << ", " << name << "!" << std::endl;
};
std::function<void(const std::string&)> callback2 = lambdaCallback;
executeCallback(callback2, "Bob"); // 输出: Greetings from Lambda, Bob!
// C. 存储一个函数对象 (Functor)
MyFunctor functor("Hi from Functor");
std::function<void(const std::string&)> callback3 = functor;
executeCallback(callback3, "Charlie"); // 输出: Hi from Functor, Charlie!
// D. 存储一个成员函数
// 需要使用 std::bind 或捕获 this 的 Lambda
EventProcessor processor;
// 使用 std::bind
std::function<void(const std::string&)> callback4 =
std::bind(&EventProcessor::process, &processor, std::placeholders::_1);
executeCallback(callback4, "Data X"); // 输出: Processing data: Data X
// 也可以用 Lambda 捕获 this
auto memberLambdaCallback = [&](const std::string& data) {
processor.process(data);
};
std::function<void(const std::string&)> callback5 = memberLambdaCallback;
executeCallback(callback5, "Data Y"); // 输出: Processing data: Data Y
// 尝试调用一个空的 std::function
std::function<void(const std::string&)> emptyCallback;
executeCallback(emptyCallback, "Dave"); // 输出: Callback is empty!
return 0;
}这段代码展示了
std::function
std::function
在
std::function
立即学习“C++免费学习笔记(深入)”;
函数指针的局限性: 最原始的回调方式是使用函数指针。它简单直接,但问题在于,函数指针只能指向自由函数或静态成员函数,它们无法携带任何“状态”信息。这意味着如果你想让回调函数访问某个对象的数据,或者执行某个对象的特定方法,函数指针就无能为力了。你可能需要通过
void*
this
static_cast
成员函数回调的复杂性: 如果你想把一个类的成员函数作为回调,那就更麻烦了。成员函数需要一个对象实例来调用,不能直接用函数指针。经典的解决方案是使用
std::bind
boost::bind
std::bind
Lambda 表达式的出现,但缺乏统一接口: C++11 引入了 Lambda 表达式,这无疑是回调机制的一大福音。它们可以捕获外部变量,写起来简洁明了。但问题是,每个 Lambda 表达式都有一个独一无二的、编译器生成的类型。你无法直接声明一个参数类型是“任意 Lambda 表达式”的函数。你可能需要使用模板,但如果你的函数需要存储这些 Lambda 表达式(比如一个事件分发器),模板就显得不那么灵活了,你不能在一个
std::vector
std::function
std::bind
std::function
std::bind
这几者在 C++ 的可调用对象体系中扮演着不同的角色,理解它们的异同对于写出高效且可维护的代码至关重要。我经常看到有人把它们混淆,或者在不恰当的场景下使用,结果导致代码要么臃肿,要么效率低下。
函数指针 (Function Pointers):
std::function
Lambda 表达式 (Lambda Expressions):
std::function
std::sort
std::for_each
std::function
std::bind
std::bind
std::function
void MyClass::handler(int)
void(int)
std::function
std::bind
this
std::function
std::function
std::bind
简单来说,Lambda 和
std::bind
std::function
std::function
std::function
std::function
调用空的 std::function
std::function
nullptr
std::bad_function_call
std::function
std::function
operator bool()
if (myCallback)
std::function<void()> func;
if (func) {
func(); // 安全调用
} else {
std::cout << "func is empty!" << std::endl;
}捕获外部变量的生命周期问题(Dangling References): 当 Lambda 表达式通过引用 (
&
std::function
std::function
=
[var_name]
std::shared_ptr
std::shared_ptr
std::function
std::function<void()> callback;
{
int x = 10;
// 错误示例:按引用捕获,x 离开作用域后悬空
// callback = [&]() { std::cout << x << std::endl; };
// 正确示例:按值捕获
callback = [x]() { std::cout << x << std::endl; };
} // x 在这里销毁
if (callback) {
callback(); // 如果是按引用捕获,这里会是未定义行为
}递归 Lambda 与 std::function
std::function
std::function
std::function<int(int)> factorial;
factorial = [&](int n) {
if (n <= 1) return 1;
return n * factorial(n - 1); // 捕获并调用自身
};
std::cout << factorial(5) << std::endl; // 输出 120std::function
堆内存分配 (Heap Allocation):
std::function
std::function
std::function
std::function
间接调用 (Indirect Call) 开销:
std::function
拷贝开销:
std::function
std::function
std::function
const std::function&
std::function&&
何时需要担心性能?
std::function
template<typename Callable>
总的来说,
std::function
以上就是C++如何使用std::function实现通用回调的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号