std::function的介绍和使用
std::function是一个可变参类模板,是一个通用的函数包装器(Polymorphic function wrapper)。std::function的实例可以存储、复制和调用任何可复制构造的可调用目标,包括普通函数、成员函数、类对象(重载了operator()的类的对象)、Lambda表达式等。是对C++现有的可调用实体的一种类型安全的包裹(相比而言,函数指针这种可调用实体,是类型不安全的)。
std::function中存储的可调用对象被称之为std::function的目标。若std::function中不含目标,调用不含目标的std::function会抛出std::bad_function_call 异常。
看到这里我们一定会疑惑,std::function到底怎么将可调用目标存储起来的?怎么为不同可调用目标提供通用的“包装”?
我们将这些疑问暂时放下,先看一下如何使用std::function。
std::function源码分析
std::function模板类的定义如下,有一个标准函数指针类型的成员变量_M_invoker。
std::function涉及到的几个类之间的简化关系:
-
function的函数指针成员变量_M_invoker被初始化为_Function_handler的成员函数_M_invoker;_M_invoker调用了接管的可调用对象;
-
四个特化版本均继承自_Function_base::_Base_manager。
-
其中第一个和第二个特化版本存储的可调用目标是普通函数、类实例或者Lambda表达式,两个特化版本的区别为第一个存储的可调用目标有返回值,第二个存储的可调用目标没有返回值;
-
其中第三个和第四个特化版本存储的可调用目标是类的成员函数,区别在于成员函数是否有返回值。
-
每一个特化版本均包含一个静态函数_M_invoke,使用该函数初始化function::_M_invoker,在该函数中完成可调用目标的调用。
-
-
function的基类_Function_base的成员_M_functor真正接管可调用对象,当可调用对象的大小大于两个指针时存储在堆上,_M_functor指向存储位置;
- 所以当接管的可调用对象的大小大于2个指针大小时,就会动态分配内存。否则就会直接使用_M_pod_data作为存储空间,直接存储可调用对象。
- 普通函数指针的大小为一个指针大小,类成员函数指针的大小为2个指针,Lambda表达式、类对象的大小均有可能大于一个指针大小,甚至大于两个指针大小,取决于其成员变量的数量。
-
_Function_base的内部类_Base_manager提供接口函数。
ase的内部类_Base_manager提供接口函数。**