全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

c++中的Type Erasure(类型擦除)技术是什么_c++ std::function实现原理【高级】

类型擦除是C++中通过统一接口隐藏具体类型、实现运行时多态的惯用法,典型应用有std::function、std::any等;其核心是控制块封装构造/拷贝/析构/调用函数指针,并常结合小对象优化避免堆分配。

类型擦除(Type Erasure)是 C++ 中一种实现“运行时多态但不依赖继承”的高级技巧,核心思想是:**把具体类型的接口统一包装成某个固定接口,在外部完全隐藏底层类型信息**。它不是语言特性,而是一套惯用法(idiom),std::function、std::any、std::variant(部分)、boost::any 等都是其典型应用。

为什么需要类型擦除?

传统虚函数多态要求所有类型继承同一基类,且必须在编译期确定继承关系;而 std::function 要能存储任意可调用对象(lambda、函数指针、bind 表达式、仿函数类……),它们彼此毫无继承关系,类型千差万别。类型擦除绕开了继承约束,靠“间接层 + 统一接口 + 动态分发”达成泛化存储与调用。

std::function 是怎么做到“装下任意 callable”的?

std::function 的关键在于内部持有一个指向**类型无关的虚函数表(vtable)风格函数指针集合**的指针,以及一块能容纳各种大小对象的缓冲区(小对象优化 SOO)。它不直接存 T,而是存一个“类型擦除后的控制块(control block)”,该控制块里封装了:构造、拷贝、析构、调用这四类操作的函数指针。

例如,当你写:

std::function f = [](int x) { return x * 2; };

编译器会为这个 lambda 生成一个匿名类型(比如 lambda_abc123),然后在堆上(或栈内 SOO 区域)构造一个控制块,其中:

  • construct 指向一个函数:负责在指定内存位置 placement-new 构造该 lambda 实例
  • copy 指向一个函数:调用该 lambda 的拷贝构造
  • destroy 指向一个函数:显式调用析构函数
  • invoke 指向一个函数:从内存中取出 lambda 并调用 operator()

std::function 对象本身只保存一个 void* 指针(指向数据)和一组函数指针(指向上述操作),对外彻底屏蔽了 lambda 的真实类型。

手写一个极简 Type Erasure 示例(仿 std::function)

以下是一个仅支持无参无返回值 callable 的简化版:

class any_callable {
  struct concept {
    virtual ~concept() = default;
    virtual void invoke() = 0;
    virtual concept* clone() const = 0;
  };

  template
  struct model : concept {
    T data;
    model(T&& x) : data(std::move(x)) {}
    void invoke() override { data(); }
    concept* clone() const override { return new model{data}; }
  };

  std::unique_ptr p;
public:
  template
  any_callable(F&& f) : p(std::make_unique>>(std::forward(f))) {}
  void operator()() { p->invoke(); }
};

这就是类型擦除的本质:用基类指针(concept*)抹去 T 的身份,靠模板特化(model)为每个 T 生成专属实现,再通过虚函数完成动态分发。

现代优化:小对象优化(SOO)与避免堆分配

真实 std::function 通常不总用 new —— 它会在对象内部预留一小段内存(如 32 字节),若待存 callable 的大小 ≤ 该阈值,就直接 placement-new 到内部缓冲区,避免堆分配开销。这需要对齐计算、类型大小/对齐检查、手动调用构造/析构等底层操作,也是其实现复杂的关键原因之一。

SOO 带来两个关键判断逻辑:

  • 是否足够小?→ sizeof(T) ≤ buffer_size && alignof(T) ≤ buffer_alignment
  • 如何构造?→ 用 ::new(buffer) T(std::move(t)),而非 new T(std::move(t))

std::function 的 move 构造/赋值也高度依赖 SOO 状态,需区分“堆上对象”和“内嵌对象”分别处理。

基本上就这些。类型擦除不是魔法,它是以空间换灵活、以间接换通用的工程权衡——理解它,你就看懂了现代 C++ 泛型库的骨架之一。


# 字节  #   # c++  # 为什么  # 封装  # 多态  # 析构函数  # const  # int  # void  # Lambda  # 指针  # 继承  # 虚函数  # 接口  #   # class  # public  # Struct  # operator  # 泛型  # copy  # function  # 对象  # default  # 擦除  # 一个函数  # 都是  # 是一个  # 特化  # 你就  # 这就是  # 是怎么  # 千差万别 


相关文章: 如何用免费手机建站系统零基础打造专业网站?  如何在企业微信快速生成手机电脑官网?  Swift中循环语句中的转移语句 break 和 continue  香港代理服务器配置指南:高匿IP选择、跨境加速与SEO优化技巧  如何实现建站之星域名转发设置?  如何快速使用云服务器搭建个人网站?  如何安全更换建站之星模板并保留数据?  宝塔建站无法访问?如何排查配置与端口问题?  制作ppt免费网站有哪些,有哪些比较好的ppt模板下载网站?  c++ stringstream用法详解_c++字符串与数字转换利器  logo在线制作免费网站在线制作好吗,DW网页制作时,如何在网页标题前加上logo?  建站之星导航菜单设置与功能模块配置全攻略  已有域名如何免费搭建网站?  沈阳制作网站公司排名,沈阳装饰协会官方网站?  香港服务器网站卡顿?如何解决网络延迟与负载问题?  如何处理“XML格式不正确”错误 常见XML well-formed问题解决方法  西安专业网站制作公司有哪些,陕西省建行官方网站?  金*站制作公司有哪些,金华教育集团官网?  如何通过网站建站时间优化SEO与用户体验?  佛山网站制作系统,佛山企业变更地址网上办理步骤?  网站图片在线制作软件,怎么在图片上做链接?  建站之星安装需要哪些步骤及注意事项?  赚钱网站制作软件,建一个网站怎样才能赚钱?是如何盈利的?  网站制作公司哪里好做,成都网站制作公司哪家做得比较好,更正规?  网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?  建站之星上传入口如何快速找到?  建站之星安全性能如何?防护体系能否抵御黑客入侵?  Swift中swift中的switch 语句  建站之星后台搭建步骤解析:模板选择与产品管理实操指南  如何通过VPS建站实现广告与增值服务盈利?  制作假网页,招聘网的薪资待遇,会有靠谱的吗?一面试又各种折扣?  北京网站制作费用多少,建立一个公司网站的费用.有哪些部分,分别要多少钱?  C++如何编写函数模板?(泛型编程入门)  如何快速完成中国万网建站详细流程?  高性能网站服务器部署指南:稳定运行与安全配置优化方案  在线教育网站制作平台,山西立德教育官网?  制作网站的软件下载免费,今日头条开宝箱老是需要下载怎么回事?  太平洋网站制作公司,网络用语太平洋是什么意思?  网站制作服务平台,有什么网站可以发布本地服务信息?  陕西网站制作公司有哪些,陕西凌云电器有限公司官网?  如何规划企业建站流程的关键步骤?  如何通过西部建站助手安装IIS服务器?  早安海报制作网站推荐大全,企业早安海报怎么每天更换?  如何通过wdcp面板快速创建网站?  已有域名和空间如何快速搭建网站?  如何正确下载安装西数主机建站助手?  宝盒自助建站智能生成技巧:SEO优化与关键词设置指南  ,制作一个手机app网站要多少钱?  实现虚拟支付需哪些建站技术支撑?  广东企业建站网站优化与SEO营销核心策略指南 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。