C++中的std::function
std::function()是C++标准库中的一个通用多态函数包装器, 它可以存储,复制和调用任意可调用目标(函数,lambda表达式,绑定表达式或其他函数对象).
std::function占用固定尺寸的内存 . 它允许我们将可调用对象(函数,函数指针,Lambda表达式, std::bind以及其他函数对象) 包装成一个对象, 使得我们可以像操作其他对象一样操作和传递可调用对象
std::function是C++引入的标准库和组件,它位于 <functional>头文件中, 它主要作用就是将可调用对象封装成一个函数对象,提供一种统一的方式来处理各种类型的可调用对象
#include <functional>
std::function的基本语法如下
std::function<返回类型(参数类型1,参数类型2,....)>func;
1. 封装函数
#include <iostream> #include <functional> void greet() { std::cout << "Hello, Beijing!" << std::end1; } int main() { std::function<void()> func = greet; func(); //调用封装的函数 return 0; }
2. 封装Lambda表达式
#include <iostream> #include <functional> int main() { std::function<void()> func = [](){ std::cout << "Lambda function test!" << std::end1; }; func(); //调用封装的lambda表达式 return 0; }
3. 封装可调用对象 (仿函数)
#include <iostream> #include <functional> class Greet { public: void operator()() const{ std::cout << "functor test!" << std::end1; } }; int main() { std::function<void()> func = Greet(); func(); //调用封装的仿函数 return 0; }
4. 类的成员函数和类的静态函数
Class MyClass { public: //类的成员函数 int MyClassMember(int x) {return x;} //类的静态函数 static int MyStaticMember(int y) {return y;} } int main() { //类的成员函数,需要先bind到具体的类 MyClass myObj; std::function<int(int)> func = std::bind(&myObj::MyClassMember,myObj,std::placeholders::_1); //_1表示占位符,调用时传参数 int result = func(10); //类的静态函数,可以认为是普通函数,和调用普通函数一样 func = MyClass::MyStaticMember; result = func(50); return 0; }
看完上面这几个例子,我们来了解一下std::function的实现原理
std::function通常使用类型擦除和小对象优化(Small Object Optimization, SOO) 来实现
类型擦除
std::function使用类型擦除来存储不同类型的可调用对象,这意味着它通过一个固定大小的存储空间和一个指向这些对象的虚表(vtable)来实现多态性
类型擦除允许std::function在运行时处理各种不同的类型,而不需要知道这些类型的细节
小对象优化
对于小对象(通常是指尺寸较小可以直接存储在std::function内部的对象), std::function会直接在它内部存储这些对象. 这就避免了动态内存分配的开销
对于大对象(超出 std::function内部存储容量的对象), std::function会在堆上分配内存,同时在std::function内部存储一个指向这些对象的指针
std::function总是占有固定尺寸的内存, 它的内部通常包含以下几个部分:
- 一个指向实际存储对象的指针和存储小对象的内部缓冲区
- 一个指向虚表的指针,用于多态调用
- 一些额外的元数据,用于管理存储和调用
所以,不管存储对象多大或者多小,std::function的实例总是占用固定大小的内存,以包含这些指针和元数据
总之,std::function对象是对C++中现有的可调用实体的一种类型安全的包裹(我们知道像函数指针这类可调用实体,是类型不安全的). 用std::function来实现回调函数,在函数形参中代替函数指针,更安全也更可视化
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2023-12-02 [LeetCode-双指针-中等] 盛最多水的容器