std::function因运行时开销、不支持多播及不可比较而受限;需自实现模板化delegate,核心是用void*+函数指针统一存储可调用对象并提供invoke接口。

为什么不能直接用 std::function?
多数场景下,std::function 完全够用,但它有运行时开销(类型擦除、堆分配可能)、不支持多播(一次调用多个目标),且无法比较两个实例是否绑定到同一函数对象。如果你需要轻量、可比较、支持 +=/-= 的委托行为(比如事件系统),就得自己实现模板化委托。
Delegate 模板的基本结构怎么写?
核心是把可调用对象(函数指针、成员函数指针、lambda)统一存为一个泛型包装,并提供统一的 invoke() 接口。关键点在于:用模板参数推导签名,用 void* + 函数指针保存目标,避免虚函数或动态分配。
典型结构:
template<typename r typename... args>
class Delegate {
using FuncPtr = R(*)(void*, Args...);
void* m_target = nullptr;
FuncPtr m_func = nullptr;
<p>public:
template<typename t typename m>
Delegate(T* obj, M method) : m_target(obj), m_func(&invoke_member<t m>) {}</t></typename></p>
<pre class="brush:php;toolbar:false;">template<typename f>
Delegate(F&& f) : m_target(new std::decay_t<f>(std::forward<f>(f))),
m_func(&invoke_functor<:decay_t>>) {}
R operator()(Args... args) const { return m_func(m_target, std::forward<args>(args)...); }</args></:decay_t></f></f></typename>
private:
template
template<typename f>
static R invoke_functor(void* f_ptr, Args... args) {
return (*static_cast<f>(f_ptr))(std::forward<args>(args)...);
}</args></f></typename>
};
注意:invoke_member 里用 reinterpret_cast<m>(nullptr)</m> 是为了获取函数类型,实际调用时再 cast 回去——这是标准做法,但要求编译器支持非静态成员函数指针的正确 reinterpret_cast(GCC/Clang/MSVC 都支持)。
如何支持多播和可比较性?
单播委托容易实现,但多播(+=)需要容器;可比较性要求能判断两个 Delegate 是否绑定到同一个对象+同一方法。这意味着不能只比 m_target 和 m_func 地址——因为 lambda 可能每次构造都不同,但语义相同。
- 安全做法:只对函数指针、成员函数指针做精确地址比较;对 functor 类型,仅当它们是同一对象实例(如
&obj+ 同一std::function实例)才认为相等 - 多播推荐用
std::vector<delegate args...>></delegate>,但需重载operator+=并检查重复(靠地址比较) - 避免在 functor 构造时做深拷贝——否则
operator==失效;建议只接受左值引用或 move-only 类型
容易踩的坑有哪些?
最常见的是生命周期问题:委托持有裸指针(如 this),但目标对象提前析构,调用时崩溃。
- 不要在栈对象上绑定成员函数后,把委托存到别处——除非你能保证对象生命周期长于委托
- lambda 捕获局部变量后存入委托,同样危险;改用
std::shared_ptr管理捕获对象(需修改委托内部存储逻辑) - 成员函数指针大小在不同平台可能不同(尤其多重继承下),
sizeof(MFPtr)不一定等于sizeof(void*);所以不要试图把 MFPtr 强转成void*存——必须用独立字段或联合体 - MSVC 对空基类优化更激进,某些 functor 的
sizeof为 1,但new分配后地址对齐可能影响比较结果
真正健壮的委托系统往往要配合 weak_ptr 或回调注册表来管理生命周期,模板层只能解决类型和调用问题,内存安全得靠使用约定或额外机制兜底。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











