。
为什么C++中有函数指针还需要std::function?C/C++中可以使用指针指向一段代码,这个指针就叫函数指针,假设有这样一段代码:
#include <stdio.h>int func(int a) { return a + 1; }int main() {int (*f)(int) = func;printf("%p\n", f);return 0;}
我们定义了一个函数func,然后使用指针变量f指向该函数,然后打印出变量f指向的地址,代码很简单,然后我们编译一下,看下编译后生成的指令 , 我们重点关注func函数:
int func(int a) {4005b6: 55push%rbp4005b7: 48 89 e5mov%rsp,%rbp4005ba: 89 7d fcmov%edi,-0x4(%rbp)return a + 1;4005bd: 8b 45 fcmov-0x4(%rbp),%eax4005c0: 83 c0 01add$0x1,%eax}4005c3: 5dpop%rbp4005c4: c3retq
可以看到,编译好后的函数func位于地址0x4005b6这个地址,让我们记住这个地址 。然后运行一下编译后生成的程序,想一想这段代码会输出什么呢?显然应该是func函数的在内存中的地址!
[root@localhost 07]# ./a.out0x4005b6
没有猜错吧 , 实际上函数指针本质也是一个指针,只不过这个指针指向的不是内存中的一段数据而是内存中的一段代码,就像这样:
文章插图
看到了吧,我们常说的指针一般都是指向内存中的一段数据,而函数指针指向了内存中的一段代码,在这个示例中指向了内存地址
0x4005b6
,在这个地址中保存了函数func
的机器指令 。现在你应该明白函数指针了,细心的同学可能会有一个疑问,为什么编译器在生成可执行文件时就知道函数
func
存放在内存地址0x4005b6
上呢?这不应该是程序被加载到内存后开始运行时才能确定的吗?函数指针的作用是可以把一段代码当做一个变量传来传去,主要的用途之一就是回调函数 。关于回调函数其实是在A模块定义,在B模块被调用,就像这样:
文章插图
然而有时我们会有这样的场景,我们依然需要在模块A定义函数 , 同时函数A的运行需要依赖B模块产生的数据,然后将模块A定义的函数和模块B产生的数据一并传递给C模块来调用,就像这样:
文章插图
此时,单纯的函数指针已经不够用了,因为函数指针只是单纯的指向了内存中的一段代码,我们不但需要将内存中的一段代码同时也需要将内存中的一块数据传递给模块C,此时你可以定义一个结构体 , 将代码和数据打包起来 , 就像这样:
typedef void (*func)(int);struct functor {func f;int arg;};
我们将这个结构体命名为functor
,注意看,这个结构中有两部分:- 一个指向代码的指针变量
- 一个保存数据的变量
void run(struct functor func) {func->f(func->arg);}
即,functor既包含了一段代码也包含了这段代码使用的数据,这里的数据也被称为context,即上下文,或者environment,即环境,不管怎么称呼,其实就是函数运行依赖的数据:文章插图
而这也正是C++中
std::function
的目的所在 。单纯的函数指针并没有捕捉上下文的能力,这里的上下文就是指代码依赖的数据,你不得不自己动手构造出一个结构体用来存储代码依赖的上下文 。在C++中你没有办法单纯的利用函数指针指向对象的成员函数,就是因为函数指针没有办法捕捉
this
(指向对象的指针)这个上下文 。?注:利用std::function
的作用本质上和我们刚才定义的结构体区别不大 。
std::function
你不但可以保存一段代码,同时也可以保存必要的上下文,然后在合适的地方基于上下文调用这段代码 。根据上文的介绍,我们也知道
std::function
相比函数指针的优势所在,要去理解std::function
,只需要理解上面提到的结构体即可 。接下来我们来谈谈std::function
的用法以及一步一步实现一个简单的std::function
,剖析其原理 。function的基本用法接下来直接展示function的直观用法,我们可以把function想象为一个模板类,调用该模板类的
operator()()
小括号运算符重载,执行封装的函数指针,关于
推荐阅读
- .net core Blazor+自定义日志提供器实现实时日志查看器
- 小样本利器4. 正则化+数据增强 Mixup Family代码实现
- 学习ASP.NET Core Blazor编程系列九——服务器端校验
- nginx 客户端返回499的错误码
- 三、Go环境安装
- 100版本dnf如何给武器镶嵌徽章(dnf如何在装备上镶嵌徽章)
- oppoa93参数配置详情_oppoa93参数配置详情处理器
- 崩坏3武器索尔之锤强度如何
- 天玑1100相当于骁龙多少处理器_天玑1100相当于骁龙什么水平
- 我的世界暗物质武器怎么做(我的世界暗物质套怎么合成)