当前位置: 首页 > news >正文

C++ 中emplace系列函数

  • emplace的原地构造核心是定位 new(placement new):在容器已分配的内存地址上,直接调用元素的构造函数创建对象;
  • 借助完美转发传递构造参数,自动匹配元素的对应构造函数,无需提前创建临时对象;
  • 相比push系列函数,emplace避免了临时对象的创建、拷贝 / 移动和销毁,效率更高(尤其适合不可拷贝对象如std::thread、大对象如std::function)。

一、核心结论先明确

emplace系列函数(emplace/emplace_back/emplace_front等)确实是直接调用元素的构造函数,并且是在容器为元素分配好的内存空间里 “就地” 构造,全程不会创建临时对象,这也是它比push/push_back更高效的核心原因。

二、emplace 的原地构造实现原理

要理解原地构造,我们先对比push_backemplace_back的区别,再拆解底层实现:

1. 先看 “非原地构造” 的例子(push_back)

比如给vector<std::thread>添加元素时用push_back

// 错误示例:std::thread不可拷贝,push_back会先创建临时thread,再尝试移动/拷贝 // 即使能移动,也会多一次临时对象的创建+销毁 std::vector<std::thread> vec; vec.push_back(std::thread([]() { /* 线程逻辑 */ }));

push_back的执行流程:

  1. 先在当前代码行创建一个临时的std::thread对象(调用std::thread的构造函数);
  2. 容器(vector)为新元素分配内存;
  3. 将临时对象移动 / 拷贝到容器分配的内存中;
  4. 销毁临时对象(调用std::thread的析构函数)。

简单说:push_back是 “先造好对象→再搬到容器里”,中间多了临时对象的开销。

2. 再看 “原地构造” 的例子(emplace_back)

还是上面的场景,用emplace_back

std::vector<std::thread> vec; // emplace_back直接在vector的内存里构造thread对象 vec.emplace_back([]() { /* 线程逻辑 */ });

emplace_back的执行流程:

  1. 容器(vector)先为新元素分配好内存空间(确定内存地址);
  2. emplace_back接收构造std::thread所需的参数(这里是 lambda),通过完美转发std::forward)把参数传递到第一步分配的内存地址上;
  3. 定位 new(placement new)在该内存地址上直接调用std::thread的构造函数,创建对象;
  4. 全程无临时对象,无拷贝 / 移动。
3. 底层关键:定位 new(placement new)

emplace的原地构造核心依赖 C++ 的定位 new语法,它的作用是 “在指定的内存地址上创建对象”,语法形式很简单:

// 普通new:分配内存 + 构造对象 T* ptr = new T(参数); // 定位new:仅在已分配的内存上构造对象(不分配新内存) void* mem = 已分配的内存地址; T* obj = new (mem) T(参数); // 直接在mem指向的地址调用T的构造函数

容器的emplace函数内部,就是用这种方式:先通过容器的内存管理逻辑(比如 vector 的扩容、queue 的节点分配)拿到一块空内存,再用定位 new 调用元素的构造函数,把对象 “造” 在这块内存上。

4. 结合线程池代码的例子

这两行emplace,都是典型的原地构造:

// 1. workers.emplace_back([this]() { ... }) workers.emplace_back([this]() { /* 线程逻辑 */ }); // 原理:vector先为新的thread分配内存,然后直接在该内存上调用std::thread的构造函数(参数是lambda),无临时thread对象 // 2. tasks.emplace(std::move(task)) tasks.emplace(std::move(task)); // 原理:queue先为新的std::function<void()>分配节点内存,然后直接在该内存上调用std::function的移动构造函数,无临时function对象

三、emplace 为什么能匹配任意构造函数?

你可能会问:emplace怎么知道要调用元素的哪个构造函数?答案是完美转发(std::forward)emplace系列函数都是模板函数,会接收任意数量、任意类型的参数,然后通过std::forward把参数 “原样” 传递给元素的构造函数,自动匹配对应的构造版本。

比如:

  • 如果你传[](){}emplace_back,就匹配std::thread的 “接收可调用对象” 的构造函数;
  • 如果你传std::move(task)emplace,就匹配std::function的移动构造函数;
  • 如果你传10, "hello"emplace,就匹配元素的 “接收 int+const char*” 的构造函数(如果有的话)。
http://www.jsqmd.com/news/328106/

相关文章:

  • Spring Boot与微服务核心技术面试实战解析
  • 智慧文旅新场景:景区咖啡机器人核心技术解析与主流产品应用测评
  • 基金估值工具
  • Linux 驱动开发
  • 2026年四川铝单板批发厂家综合推荐与选择指南
  • 2026年智慧养老新范式:主动干预技术与医养闭环的深度实践
  • 告别ER图绘制内耗!ER图生成神器!
  • 【毕业设计】SpringBoot+Vue+MySQL 青年公寓服务平台平台源码+数据库+论文+部署文档
  • 前后端分离房屋交易平台系统|SpringBoot+Vue+MyBatis+MySQL完整源码+部署教程
  • 2026年当下宜兴顶尖的刮泥机工厂综合评估报告
  • Hadoop 架构
  • 布局华中,链接全国|瞬维智能长沙分公司正式成立!
  • 2026年仲裁咨询律师专业评测:谁是你的最优选择?
  • 2026年档案馆智能化服务与管理机器人技术深度解析及主流产品应用
  • 智慧图书馆咨询导览机器人技术深度解析与主流产品评测
  • 第 9 篇:代理模式 (Proxy) —— 硬件的“防火墙”
  • 第 8 篇:适配器模式 (Adapter) —— 换芯片不换代码
  • 【毕业设计】SpringBoot+Vue+MySQL 经方药食两用服务平台平台源码+数据库+论文+部署文档
  • OpenClaw/Moltbot自动进化技巧分享!打造全自动智能超级助手,彻底解放双手,让AI越用越聪明!能自动学习避坑!OpenClaw自动操控Claude Code,全程零干预实现规格驱动开发
  • 企业级经方药食两用服务平台管理系统源码|SpringBoot+Vue+MyBatis架构+MySQL数据库【完整版】
  • 大学生就业需求分析系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
  • 2026年临泉县外墙喷砂优质服务商深度评测与推荐
  • Java Web 高校教师电子名片系统系统源码-SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0【含文档】
  • [转]OpenClaw 一周更名两次(原名Clawdbot、Moltbot) ---- 最近爆火的个人智能助理,究竟有什么魅力???
  • 房屋交易平台信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
  • 企业级青年公寓服务平台管理系统源码|SpringBoot+Vue+MyBatis架构+MySQL数据库【完整版】
  • SpringBoot+Vue 大学生就业需求分析系统平台完整项目源码+SQL脚本+接口文档【Java Web毕设】
  • 基于SpringBoot+Vue的大学生就业需求分析系统管理系统设计与实现【Java+MySQL+MyBatis完整源码】
  • 2026年长沙沙发批发与定制家具优质厂商推荐
  • Python中 .whl 后缀文件的全称