引言


在C11中,有两种方法可以把元素放入容器中:emplace_back和push_back。

push_back是C11之前就有的,而emplace_back是C11中新加的。

既然它们的作用都是一样的,那么为什么C11中又加入了一个emplace_back?

既生瑜,何生亮?

在实际的项目编码中,到底用哪个呢?

优先选用emplace_back


考虑下面这段非常常见的代码:

std::vector<string> vs;vs.push_back("xyz");

其中,vs容器持有的是string类型的对象,而在push_back的时候传入的是字符串字面量(不是string),换句话说,传递给push_back的实参并非容器持有物的类型。

同时我们也知道,这段代码没有问题,能够通过编译并正常运行。但是它背后都执行了哪些操作呢?

我们来看一下vector的push_back,它针对左值和右值给出了不同的重载版本:

template<class T, class Allocator = alloctor<T>> // c++11标准
class vector
{public:// ...void push_back(const T& x); // 左值void push_back(T&& x); // 右值// ...
};

现在回头看一下上面的那段代码,它会从字符串字面量出发创建string类型的临时对象,并将该临时对象传递给push_back,如下:

vs.push_back(string("xyz"));

之所以要说明一下push_back后面的一些过程,是为了说明上面这句代码,虽然在功能上没有任何问题,但它可能存在性能上问题,因为它共执行了2次构造和1次析构:

  • 从字符串字面量“xyz”,创建string临时对象。临时对象没有名字,可以称为temp。这是第一次构建,因为是临时对象,所以temp是右值。
  • temp传递给push_back的右值重载版本,它被绑定到右值引用形参x。然后会在内存中为vector构造一个x的副本,这是第2次构造,在vector内创建了一个新的对象。
  • 在push_back返回的时候,temp析构。

那么,有没有方法能将字符串字面量直接传递给vector内构造的string对象,从而避免temp对象的构造和析构呢?

有!emplace_back就可以!

emplace_back使用完美转发,它使用传入的任何实参,在vector内构造一个string,不会涉及任何临时对象。

emplace_back之所以比push_back更牛逼,是因为它提供了更加灵活的接口:

  • push_back接受的是待插入对象
  • emplace_back接受的是待插入对象的构造函数实参

所以emplace_back能够避免临时对象的创建和析构。

即使在push_back燕不要求创建临时对象的情况下,也可以使用emplace_back,这时,它们两个做的是同一件事情。

综上所述,emplace_back能做到push_back所能够做到的一切事情,而且前者可能比后者更高效,那么,何不总是使用emplace_back呢?

push_back的用武之地


然而,emplace_back比push_back的效率有时更高,是理论上的。

在实际实践中,还是要根据看传递的实参类型、容器种类、插入位置、容器持有类型构造函数的异常安全性、容器是否禁止相同元素的插入等情况,对两者性能进行基准测试。

根据经验,如果下列情况都成立,那么emplace_back几乎总是比push_back的效率更高:

  • 待添加的值是以构造而非赋值方式加入容器,这个大多数标准容器都满足
  • 传递的实参类型与容器持有之物的类型不同,这时emplace_back不要求创建和析构临时对象
  • 容器不太可能由于出现重复情况而拒绝待添加的值,要么容器允许重复值,要么添加的大部分值满足唯一性。因为emplace_back会创建临时节点与容器内值比较,如果因为重复值被拒绝,构造与析构就付出了成本。

除此之外,如果要使用emplace_back,还有两个问题需要处理:

  • 涉及到资源管理。push_back会存在临时对象,当构造抛出异常时,临时对象可以正常析构释放对象
  • 与带有explicit声明饰词的构造函数之间的互动。在使用emplace_back,要特别小心去保证传递了正确的实参,因为即使是带有explicit声明饰词的构造函数也会被编译器纳入考虑范围,因为它会尽力找到某种方法来解释你的代码使它合法(即使不符合逻辑)。

以上,在emplace_back不适合使用的时候,就是push_back的用武之地了。

由于它内在机制的不同,自然也就不会造成那些隐晦的、难以调试的bug。

小结


C11可以使用emplace_back和push_back向容器内添加元素。

建议优先选用emplace_back,因为它几乎能做到push_back所能做到的一切,且可能避免性能上的一些潜在问题。

但emplace_back在一些场景下也有使用陷阱,如异常安全性、能够通过编译但可能导致未定义的行为等,在这些场合下使用push_back就可以避免这些问题。

在具体的使用场景下,选用何种方式来实现,以及真正的性能差异,需要进行基准测试。

参考资料

《Effective Modern C++》

c++11中emplace_back vs push_back相关推荐

  1. C++ 中emplace_back和push_back差异

    前言 最近看rocskdb源码,发现了大量的设计模式和C++高级特性,特此补充一下,巩固基础. 问题描述 其中关于动态数组的元素添加,代码中基本将push_back抛弃掉了,全部替换为emplace_ ...

  2. C++11使用emplace_back代替push_back

    最近在写一段代码的时候,突然很好奇C++11中对push_back有没有什么改进以增加效率,上网搜了一些资料,发现果然新增了emplace_back方法,比push_back的效率要高很多. 首先,写 ...

  3. C++11:右值引用、移动构造、std::move, 以及使用emplace_back代替push_back

    最近在写一段代码的时候,突然很好奇C++11中对push_back有没有什么改进以增加效率,上网搜了一些资料,发现果然新增了emplace_back方法,比push_back的效率要高很多. 1.右值 ...

  4. C++11:右值引用、move, 以及使用emplace_back代替push_back

    最近在写一段代码的时候,突然很好奇C++11中对push_back有没有什么改进以增加效率,上网搜了一些资料,发现果然新增了emplace_back方法,比push_back的效率要高很多. 1.右值 ...

  5. C++11介绍之vector::push_back和vector::emplace_back区别

    vector::push_back和vector::emplace_back区别 emplace_back() 和 push_back() 功能上类似,但底层实现机制是不同的.push_back() ...

  6. C++11中unique_ptr的使用

    在C++中,动态内存的管理是通过一对运算符来完成的:new,在动态内存中为对象分配空间并返回一个指向该对象的指针,可以选择对对象进行初始化:delete,接受一个动态对象的指针,销毁该对象,并释放与之 ...

  7. emplace_back和push_back对比分析

    emplace_back含义 emplace_back是C++11新引进的接口函数. emplace_back是就地构造,不用构造后再次复制到容器中.因此效率更高. push_back 简单的一个案例 ...

  8. C++11中emplace的使用

    最近在刷题的时候看别人优雅的代码,发现一个叫做"emplace"的新朋友,检索了网上的相关资料后知道,这是C++11中加入的新特性,emplace_back能通过参数构造对象,不需 ...

  9. C++11中头文件thread的使用

    C++11中加入了<thread>头文件,此头文件主要声明了std::thread线程类.C++11的标准类std::thread对线程进行了封装.std::thread代表了一个线程对象 ...

最新文章

  1. 视音频数据处理入门:RGB、YUV像素数据处理【转】
  2. nginx 配置信息
  3. python英文单词-python常用150个英文单词
  4. weblogic从入门到起飞(nodemanager)(五)
  5. struts练习-表单提交
  6. 单片机红绿灯电路灯有几种_新农村建设的太阳能路灯如何选择?
  7. java传参数的方法_java中方法的参数传递机制
  8. c语言一把钥匙只能开一把锁阅读答案,一把钥匙开一把锁阅读附答案
  9. [转载] python下求语数总分和平均值_R和python语言如何求平均值,中位数和众数
  10. SwitchHosts下载安装使用
  11. 通过python 批量导出wind系统中的基金日万份和七日年化
  12. windows下超越dirx的opencv视频转化库
  13. uniapp scroll-view组件横向滚动不生效
  14. python创建简单网站
  15. 圣剑传说 玛娜传奇(Legend of Mana)(LOM) 怪物掉落道具
  16. 计算机数据备份到u盘,技术给你说Win10系统怎么把数据备份到U盘的完全处理手段...
  17. 怎么找计算机驱动程序不正常怎么办,网卡驱动程序不正常怎么办,教您解决电脑网卡驱动程序不正常...
  18. 【权威发布】360追日团队:Xshellghost技术分析——入侵感染供应链软件的大规模定向攻击
  19. 史上最全体检表、检验报告解析
  20. 谷歌浏览器CSND广告屏蔽方法

热门文章

  1. 利用js实现论坛发帖小案例
  2. SDH与MDH参数法对比
  3. java中List的addAll方法顺序
  4. 计算机模拟应用,计算机模拟的新应用
  5. 满意度调查的发展历程
  6. mysql 多表联查
  7. 15道APP测试面试题分享,助攻你的面试
  8. 组策略统一在桌面显示计算机图标
  9. 2019-1-24【训练日记】
  10. Java读写xml文件操作(3W)what why how where