代码位于 bits/std_function.h中
1. UML类关系图

这里用到了两个union(联合体). _Any_data
有个_M_pod_data
数组,用来存储我们构造一个function时,传入的参数.比如下列代码:
cpp
void foo() {}
int main()
{
function<void()> f1(foo);
}
_M_pod_data
就是用来存储参数foo函数指针的.这个没有动态分配内存,所以是存放在栈上的。
_Nocopy_types
分别定义了四个指针,联合体的大小是根据成员变量最大为准.这里定义了一个void (_Undefined_class::*_M_member_pointer)()
,这个占用大小一般为2个指针的大小,分别用来指向类对象 和成员函数 .
2. _Function_base基类
_Function_base
定义了两个成员变量
第一个成员变量不用说了,就是用来存储function构造时候的参数.
第二个变量是一个函数指针,用来指向一个函数.稍后到_Function_handler
类会讲到
3. _Base_manager
这个类定义为_Function_base
类中.这个类提供的静态函数主要用于:
- 保存函数对象\指针
- 析构函数对象\指针
- 提供一个
_M_manager
函数用于std::function的target_type()
和target()
函数
还定义了一个静态成员变量__stored_locally
这里用到了
__is_location_invariant
来判断_Functor是否是位置不变的,确定是否可以安全存储在局部变量中(即是否可以在栈上分配).
什么叫位置不变的: 就是在不同的位置具有相同的表示,这种特性被称为位置不变 当_Functor满足以下条件时,value被设置为true:
- 如果_Functor是可复制的类型, 且满足以下条件之一:
- 是一个内置数据类型
- 是一个数组类型,且元素类型是位置不变的
- 是一个结构体类型,且每个非静态数据成员都是位置不变的
- _Functor是一个标准库类型,并且容器中的元素类型是位置不变的
- _Functor是一个标准库智能指针类型,并且指针所指向的类型是位置不变的
- 函数类型也是可复制的,所以value被设置为true
下图这俩结合使用,作用是不同版本的成员函数._Base_manager
提供了两个版本的_M_create
和_M_destroy
函数.这两个版本分别是操作_Any_data
中内存和堆上的内存.
4. _Function_handler
通过名字可以得知,这个类主要就是用来执行函数的.
这个类定义了一个静态成员函数_M_invoke
,底层调用std::__invoke_r
用来执行函数
5. function
在function头部定义了一个模板类和三个模板别名
第一个_Decay_t
作用是如果模板参数_Func
和function
不是同一个类型,那么_Decay_t
则是_Func
退化后的类型.
第二个类模板_Callable
.根绝给定的函数类型_Func
,将其退化后为_DFunc
类型;然后根据给定的参数类型_ArgTypes...
执行调用操作,得到调用结果类型_Res2
;最后,判断_Res2
是否与给定的类型_Res
相符合,如果相符合,则_Callable
继承自std::true_type
,表示可调用;否则继承自std::false_type
,表示不可调用.
第三个模板参数是一个条件,如果_Cond::value
为true,则_Requires
等价于_Tp
类型
第四个用来执行函数,将模板参数_Functor
退化
5.1 构造、析构函数
5.1.1 构造函数
注意: 这个构造函数的参数是右值引用
模板参数typename _Constraints = _Requires<_Callable<_Functor>>
,这一步检测模板参数_Functor
必须是可调用的.
逐行分析函数体代码:
首先定义一个_Handler
的别名_My_handler
,操作_My_handler
也就是操作_Function_handler
类
下面判断构造函数参数__f
是否是一个空函数.这里调用_Function_handler
的_M_not_empty_function
函数,这个函数一共有四个版本:
如果_M_not_empty_function
返回为true,那么则进入if语句块里,执行初始化.
进行初始化调用_Function_handler
的_M_init_functor
函数,第一个参数_M_functor
是从基类_Function_base
继承而来的,类型是_Any_data
.
下面是_Function_handler
的_M_init_functor
函数,初始化一个functor 底层调用
_M_create
函数,该函数接收三个参数.
- 第一个参数存放
Functor
的内存位置- 第二个参数是函数对象
- 第三个是一个特定结构体
这里第三个参数调用_Local_storage()
,这个判断_Functor是否是位置不变的。对于函数类型是可复制的,位置不变的.所以调用_M_create
的true_type
版本 则在
_Any_data
上构造对象,也就是栈上构造一个函数对象.
初始化functor
之后,回到function构造函数里.
接下来设置两个函数指针 ,分别指向_Function_handler
的_M_invoke
函数; 和_Function_handler
的_M_manager
函数.
到此为止,整个构造过程结束
5.1.2 析构函数
function并没有显式的定义析构函数,而基类_Function_base
定义了析构函数.所以在析构function的时候,会调用_Function_base
显式定义的析构函数
这里判断_M_manager
函数指针是否被设置了,如果不为空,则表示已经初始化了functor.这里调用_Function_base
的静态成员函数_M_manager
.注意,第三个参数传入为 __destroy_functor,表示销毁functor
底层调用
_M_destroy
函数来销毁functor.因为_M_destroy
也有两个版本,所以第二个参数传入_Local_storage()
来匹配合适的版本.
两个版本一个销毁存储在
_Any_data
上的,一个销毁在堆上的.
5.2 拷贝、移动构造函数
5.2.1 拷贝构造

首先判断参数__x
是否是一个已经初始化functor的了. static_cast<bool>(__x))
这个代码则调用operator bool()
函数
底层调用
_M_empty
如果参数__x
不为empty的话,则进入到if语句块,进行拷贝.
调用
_M_manager
函数,第三个参数为__clone_functor
表示拷贝functor
最后复制参数
__x
的函数指针_M_invoker
和_M_manager
5.2.2 移动构造
移动构造相对简单,直接设置变量就可以了
5.3 operator=赋值运算符
拷贝运算符
移动运算符
赋值为nullptr运算符 如果先前已经初始化了functor,则调用
_M_manager
,传入参数__destroy_functor
销毁创建的functor,随后将函数指针都设置为nullptr
5.4 operator()(_ArgTypes... __args)函数调用运算符

调用之前首先检查是否已经初始化了functor,如果没有则抛出异常终止程序.否则调用一个函数指针_M_invoker
.定义为function类的末尾.
在构造函数的时候已经设置将这个函数指针指向
_Function_handler
类的_M_invoke
函数
上面这里将functor和函数所需参数都传入.
_Function_handler
的静态函数_M_invoke
,最终调用标准库__invoke_r
函数.最终执行函数调用.
5.5 target_type()获取函数对象类型
定义一个临时变量
__typeinfo_result
,用来存储当前函数对象的类型. 然后调用_M_manager
获取函数对象类型.
最后获取到临时变量
__typeinfo_result
里存储的函数对象类型
5.6 target()获取函数对象
