C++中push_back与emplace_back的区别
许多 C++ 开发者一直对 push_back() 和 emplace_back() 的区别感到困惑:它们究竟有何不同?这次我直接查阅了 libstdc++ 的源代码,终于彻底理解了底层实现的本质差异。下面把我的核心发现分享出来,帮助大家在实际开发中做出更高效的选择。

- allocate 源码:gcc.gnu.org/onlinedocs/…
- push_back 实现:gcc.gnu.org/onlinedocs/…
- emplace_back 实现:gcc.gnu.org/onlinedocs/…
先来看 push_back() 的工作流程。它要求传入一个已经构造好的对象(可以是左值或右值),然后在容器内部通过拷贝构造或移动构造来创建副本。换句话说,你传入一个临时对象,容器内部还需要再“复制”或“移动”一次,这就会多产生一次对象构造的开销。
// GCC libstdc++ vector
void push_back(const value_type& __x) {
if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) {
// 空间足够,在已开辟的内存上【拷贝构造】新对象
this->_M_impl.construct(this->_M_impl._M_finish, __x);
++this->_M_impl._M_finish;
} else {
// 空间不足,扩容并移动/拷贝旧数据
_M_realloc_insert(end(), __x);
}
}void push_back(value_type&& __x) {
if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) {
// 空间足够,在已开辟的内存上【移动构造】新对象
this->_M_impl.construct(this->_M_impl, this->_M_impl._M_finish, std::move(__x));
++this->_M_impl._M_finish;
} else {
_M_realloc_insert(end(), std::move(__x));
}
}void
construct(pointer __p, const _Tp& __val)
{ ::new((void *)__p) _Tp(__val); } /* 直接进行拷贝/移动构造 */
而 emplace_back() 走的则是完全不同的路径——它接收的不是已经构造好的对象,而是元素类型构造函数的参数。通过可变模板参数和完美转发机制,它直接在容器预留的内存上调用元素的构造函数,从而省去了创建临时对象再拷贝或移动的中间环节,在性能上更优。
template<typename... _Args>
void
emplace_back(_Args&&... __args) {
if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) {
// 空间足够,直接在目标内存上【就地构造】
this->_M_impl.construct(this->_M_impl, this->_M_impl._M_finish,
std::forward<_Args>(__args)...);
++this->_M_impl._M_finish;
} else {
_M_realloc_insert(end(), std::forward<_Args>(__args)...);
}
}template<typename... _Args> /* 可变模版参数 */
void
construct(pointer __p, _Args&&... __args)
{ ::new((void *)__p) _Tp(std::forward<_Args>(__args)...); } /* 完美转发 */
简单总结一下两者的核心区别:
- 接口调用方式不同:
push_back()接收的是已经构造好的对象(左值或右值引用),而emplace_back()接收的是元素类型的构造参数(理解起来可能有点绕,但掌握后非常直观)。 - 底层实现机制不同:
push_back()需要先在外层创建临时对象,再通过拷贝或移动构造将其“搬入”容器;emplace_back()则直接在容器预留的内存上通过完美转发调用构造函数,完全省去了临时对象的创建与拷贝/移动步骤。对于复杂对象(如包含动态申请内存、资源管理的类型),这个性能差异非常明显,在 C++ 开发中值得优先考虑。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
Linux环境下Node.js单元测试方法详解
在Linux环境下对Node js项目进行单元测试,主流框架有Mocha、Jest和Jasmine。以Mocha为例,需先安装Node js与npm,创建package json,安装Mocha为开发依赖,建立test文件夹,编写测试用例,使用describe定义测试套件、it定义测试用例、assert断言。最后在scripts中添加test命令,通过npm
如何在Linux上全面管理Node.js依赖的实用步骤与技巧
在Linux系统上,Node js依赖管理通过npm或Yarn进行,利用package json记录依赖,配合锁定文件确保版本一致。操作包括安装工具、初始化项目、安装生产与开发依赖、更新删除依赖、提交锁定文件、最小化依赖、安全审计及使用nvm管理Node js版本。
深入剖析Linux环境下ThinkPHP框架的安全风险及应对策略
Linux环境下ThinkPHP安全取决于版本、配置与开发习惯。旧版存在preg_replace漏洞、控制器过滤不严及SQL注入风险;配置疏漏如开启调试模式、未强制路由等削弱防护。升级至6 x、关闭调试、禁用危险函数、开启强制路由、使用ORM、限制文件上传、配置防火墙与HTTPS可有效提升安全性。框架、系统、开发三位一体方能构建可靠防护。
Linux下JavaScript性能优化高效实现
在Linux环境下,JavaScript性能优化需从运行时环境、代码写法、并发处理、缓存策略、数据库优化、网络优化、监控分析、安全部署及代码分割等多环节进行迭代改进,持续精准解决性能瓶颈。
全面详解Node.js在Linux系统中的安全性保障与最佳实践
在Linux环境部署Node js应用,需从系统内核加固、服务精简、依赖审计、HTTPS加密、输入验证、权限分离、敏感信息管理及监控应急响应等多个环节进行系统安全防护,构建纵深防御体系,保障应用安全运行,确保系统稳健可靠。
- 日榜
- 周榜
- 月榜
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
相关攻略
2026-06-11 07:05
2026-06-11 07:05
2026-06-11 07:05
2026-06-11 07:05
2026-06-11 07:05
2026-06-11 07:05
2026-06-11 07:05
2026-06-11 07:05
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

