链接:functional。其中 std::function 的主体内容在 2100 多行。

先来看 function 的头部。

template

其中的 libcpp template vis 宏是用来 controlling symbol visibility 的,我们先不用管。我们先看两个继承,这两个 maybe 类是 traits 类。模板元编程常见的技巧。如果 Rp 和 ArgTypes 满足一元或者二元函数的模板模式(偏特化)的话,那么就继承相应的 unary function 或者 binary function。如果不满足的话就继承空类。其中 unary function 定义是这样。

template 

binary 类似。其实就是 typedef 了函数相关类型的空类。

接下来是 std::function 中的数据成员。我们可以看到条件编译。

#ifndef _LIBCPP_ABI_OPTIMIZED_FUNCTION

其中这个 libcpp abi optimized function 是后加的一个优化选项。可以看到原来用的是 value func 而优化之后用 policy func。具体的 patch 可以见PATCH D55045。两者究竟有什么区别呢?我们瞧瞧。

我们去跟踪 value func。可以看到 value func 的数据成员是这样的。

template 

我们看到 value func 里面有一个 buf。这个 buf 是 3 个指针长度大小。我们这里假定在 64 位机器吧。那么这个 buf 就是 24 字节。然后还有一个 func 指针指向了一个 base 对象。所以我们得到了一个重要的结论:一个 value func 就是 4 个指针长度,32字节。base 对象是干嘛的?我们跟踪一下。我们可以在代码里看到这样一句话。

// __base provides an abstract interface for copyable functors.

然后是 base 类的定义。就是一个抽象的接口,里面一大堆 = 0 的函数,说是指向一个可拷贝的函子。那这个 buf 又是干嘛的呢?我们继续挖 value func。

这是在 value func 的构造函数代码段节选。

if 

可以看到,我们的构造函数根据 sizeof Fun 有了差别。如果 buf 能装得下 Fun(并且拷贝不会抛异常)那么我们的 func 指针直接去指向 buf。并且在 buf 上构造(replacement new)我们的 Fun。如果装不下(或者拷贝抛异常)那么就只能 allocate 出来内存来存放这个 Fun 了。至于这里为什么用 unique ptr 这么迂回的方式,我也不是很懂,但是我猜测和异常有关。所以,我们又得到了一个重要的结论,如果 buf 上可以分配得下 Fun(并且拷贝不抛异常),那么直接在 Buf 上分配(栈)。否则会去 allocate 内存。

关于 value func 就说到这,value func 里面其他的东西都比较正常。其中 value func 的 swap 函数实现的也比较崎岖,感兴趣可以看看。

接下来是 policy func 了。首先我们先看 policy storage。

union 

可以看到这时候用一个 union 节省了内存。并且 small 的 size 变成了 2 个指针长度即 16 个字节。一般的函数指针是不会超过这个数的,但是其他的函子可以很膨胀。这里留一个思考题:为什么一般的函数指针不会超过 16 个字节,而不是 8 个字节?提示:成员函数指针。

这是一个配套 policy storage 使用的 traits 类。

template 

很显然,如果 Fun 满足条件那么 use small storage 里的 value 是 true,否则是 false。很简单的模板元编程。注意这里的条件没有 allocator 了。因为在 C++17 之后,std::function 就不用 allocator 了。

在看 policy func 之前,我们还得看一个类,invoker。

// __policy_invoker calls an instance of __alloc_func held in __policy_storage.

其中 fast forward 先不用管,是一个传参策略的 traits。我们看到 policy invoker 里面有一个 Call 函数指针。这个函数指针指向的函数接受 policy storage 和函子的参数,然后返回函子的返回值。为什么需要这么一个类呢?我们往下看。

// Creates an invoker that calls the given instance of __func.

这里返回了一个 policy invoker 对象,并且用 call impl 初始化了 Call 函数指针。再瞧瞧 call impl。

template 

可以看到这个 call impl 函数先判定 Fun 存储在哪里,然后就去调用它。

所以,为什么需要 invoker 呢?因为我们这里用的是(内存和指向其他内存的指针)的一个 union。所以取内存方式会不同,中间会差一层取地址的抽象(见源码的 small 和 large 的取法,small 要多一层取地址)。

而 value func 为什么可以统一取内存的方式呢?因为 value func 的指向内存的指针 func 和 buf 是分开的,即使分配到了 buf 上,value func 的 func 指针依然会指向这个 buf。所以无论如何,只要通过这个 func 指针来获取内存,一定就是没错的。没有疑问。

好了,我们可以看 policy func 了。

// __policy_func uses a __policy and __policy_invoker to create a type-erased,

可以看到首先 policy func 里面有 buf,16 个字节。然后是 invoker,8 个字节。最后是 policy 指针,8 个字节。所以加起来还是 32 个字节。其中 policy 类似于 base,也是提供如何进行基本操作的类的指针。

我们再来看看 policy func 的构造函数。

template 

和 value func 差不多。不再赘述了。注意这里的分配内存之后并没有赋值给一个指针,而仅仅是在 buf 上分配内存就完了。获取函子并调用的操作是由 invoker 做的。

我觉得 std::function 的重点就是数据成员这部分。至于相关的成员函数,我觉得都比较正常,这里就不在多说什么了。

那,就这样。

is not a function_libcxx 的 std::function 源码分析相关推荐

  1. “vector”: 不是“std”的成员_libcxx 的 std::function 源码分析

    链接:functional.其中 std::function 的主体内容在 2100 多行. 先来看 function 的头部. template<class _Rp, class ..._Ar ...

  2. std::packaged_task 源码分析

    std::packaged_task 源码分析 背景: c++ 线程池,需要对任务进行包装, packaged_task是不二之选,接下来就分析下源码具体内容 std::packaged_task 源 ...

  3. STL std::sort 源码分析

    转载自http://feihu.me/blog/2014/sgi-std-sort/ 最近在看sort源码,看到这篇博文很好,转发作为记录,转载侵权联系我删除 背景 在校期间,为了掌握这些排序算法,我 ...

  4. std::move()源码分析

    https://segmentfault.com/a/1190000020744971?utm_source=tag-newest C++11 引入右值和移动语义,其中std::move()是不可或缺 ...

  5. Google Mock(Gmock)简单使用和源码分析——源码分析

    源码分析 通过<Google Mock(Gmock)简单使用和源码分析--简单使用>中的例子,我们发现被mock的相关方法在mock类中已经被重新实现了,否则它们也不会按照我们的期待的行为 ...

  6. 以太坊C++客户端Aleth源码分析,转账交易和智能合约的入口代码

    本文主要记录以太坊C++客户端Aleth的源码分析和相关实验过程和结果.本文将讲解两部分的内容,一是转账交易和智能合约的入口代码在哪里?二是通过实验验证转账交易和智能合约交易这两种不同交易所对应的不同 ...

  7. openmp官方源码_MNN推理过程源码分析笔记(一)主流程

    在正式开始推理代码分析之前, 回顾下 MNN整体结构 推理分为三个大部分 Engine Backends Runtime Optimize 那么问题来了,从哪里开始,怎么入手呢? 我的心得是源码分析不 ...

  8. Nmap源码分析(脚本引擎)

    Nmap提供了强大的脚本引擎(NSE),以支持通过Lua编程来扩展Nmap的功能.目前脚本库已经包含300多个常用的Lua脚本,辅助完成Nmap的主机发现.端口扫描.服务侦测.操作系统侦测四个基本功能 ...

  9. sigslot库源码分析

    言归正传,sigslot是一个用标准C++语法实现的信号与槽机制的函数库,类型和线程安全.提到信号与槽机制,恐怕最容易想到的就是大名鼎鼎的Qt所支持的对象之间通信的模式吧.不过这里的信号与槽虽然在概念 ...

最新文章

  1. Spark通过YARN提交任务不成功(包含YARN cluster和YARN client)
  2. UE4用音乐音效,各种声音都有,比较全了
  3. Linux查看某个进程的线程
  4. [欧拉路]CF1152E Neko and Flashback
  5. TouTiao开源项目 分析笔记7 加载数据的过程
  6. 关于y7000安装Ubuntu的一些心得体会
  7. 互联网1分钟 |1109
  8. 【Linux网络编程】TCP网络编程中connect listen和accept三者之间的关系
  9. php var_export与var_dump 输出的不同
  10. LeetCode 1139. 最大的以 1 为边界的正方形(DP)
  11. 揭秘基于MBSE集成化的汽车电子解决方案
  12. AI(2)---机器学习产品交互设计原则
  13. linux 下把整数转化为字符串
  14. 埋藏式心脏复律除颤器的原理及参数设置
  15. element环境插件
  16. 论文阅读——Shadow Attacks:Hiding and Replacing Content in Signed PDFS
  17. ESP32开发路程蓝牙篇——BLE(GATT),修改设备名称,添加characteristic,发送数据,接收数据
  18. Java编程——subString,截取当前字符串的部分内容
  19. kubernetes apiserver源码分析二之路由
  20. JAVA POI获取excel单元格红色字体,淡蓝色前景色的内容

热门文章

  1. mysql安全性特点_MySQL数据库有哪些特点?为何能得到了广泛应用?
  2. rtt面向对象oopc——4.IO设备管理之父类调用子类方法
  3. r语言数据变量分段_使用R语言实现数据分段
  4. iceberg对接flinksql测试
  5. 30号晚直播丨数据操作加速器,CloudQuery v1.3.5 发布!
  6. 高手过招:用SQL解决环环相扣的刑侦推理问题(罗海雄版本)
  7. 刑侦高考:如何用SQL解决环环相扣的刑侦推理问题
  8. 云小课|ModelArts Pro 视觉套件:零代码构建视觉AI应用
  9. 空中交警:借你一双“慧眼”,让你看透这飞机的“黑色十分钟”
  10. 14天1000+大集群滚动升级,银行柜台竟然毫无感觉