push_backemplace_back 的区别

  1. push_back

    • 功能:将一个对象(或其副本)添加到 vector 的末尾。
    • 参数:接受一个对象(或其副本)的引用。
    • 过程
      • 如果传入的是一个临时对象或一个已有对象,push_back 会创建该对象的副本(或者通过移动构造函数将其移动到 vector 中)。
      • 可能会涉及到复制构造函数或移动构造函数,特别是在添加复杂对象时,这可能会带来额外的性能开销。
    • 示例
      std::vector<std::string> vec;
      std::string str = "Hello";
      vec.push_back(str); // 复制 str 到 vector 的末尾
      vec.push_back("World"); // 复制临时字符串到 vector 的末尾
  2. emplace_back

    • 功能:在 vector 的末尾直接构造一个对象,避免了不必要的复制或移动。
    • 参数:接受对象构造函数的参数,这些参数会被直接传递给对象的构造函数。
    • 过程
      • 直接在 vector 的末尾构造对象,无需创建临时对象或复制现有对象。
      • 这通常会提高性能,尤其是在构造复杂对象时,因为它避免了不必要的中间步骤。
    • 示例
      std::vector<std::string> vec;
      vec.emplace_back("Hello"); // 直接在 vector 的末尾构造 std::string 对象
      vec.emplace_back("World", 5, 'X'); // 直接在 vector 的末尾构造 std::string 对象,使用构造函数参数

让我们用更简单的语言来解释“原地构造”以及它如何通过构造函数参数转发来实现。

原地构造的解释

原地构造是指在一个已经分配好的内存位置上直接创建一个对象。这个过程避免了创建临时对象和额外的复制操作,从而提高效率。

比喻

想象你有一个大空盒子(内存),你已经把这个盒子放在了一个特定的位置(比如一个房间的角落)。你现在要在这个盒子里直接组装一个玩具(对象),而不是先组装一个玩具,然后再把它放到盒子里。这就是原地构造——直接在那个空盒子里组装玩具,省去了中间的步骤。

构造函数参数转发

构造函数参数转发的作用是把你传给构造函数的参数直接传递给对象的构造函数,而不需要先创建一个临时对象。这可以避免不必要的复制,并提高效率。

示例

假设你有一个容器(比如 std::vector),你想要把一个新对象添加到容器中。传统的方法可能是:

  1. 创建一个临时对象:在你把对象放到容器里之前,你首先要创建一个临时对象。
  2. 将临时对象添加到容器:然后把这个临时对象复制到容器中。

这两个步骤可能很耗时间,尤其是当对象比较复杂时。

原地构造通过构造函数参数转发可以简化这个过程:

  • 原地构造:在已分配好的内存位置直接构造对象,避免了不必要的中间步骤和复制。
  • 构造函数参数转发:将参数直接传递给构造函数,使得对象可以在目标位置直接构造,而不需要创建临时对象。

通过原地构造和参数转发可以让程序更加高效,特别是在处理大量数据或复杂对象时。

构造函数参数转发的基本概念

构造函数参数转发是 C++ 中的一种技术,它允许你将传递给一个函数的参数直接传递给另一个构造函数。这通常通过完美转发(perfect forwarding)来实现。完美转发确保了参数的类型和值特性(如左值、右值)能够保持不变,避免了不必要的复制或移动。

逻辑解析

  1. 目标

    • 直接在目标位置构造对象,避免创建临时对象和多次复制。
  2. 过程

    • 构造函数参数:当你调用一个成员函数(例如 emplace_back)时,传递给它的参数是用于构造一个新对象的。
    • 完美转发emplace_back 这种函数会使用完美转发,将这些参数原样传递给目标对象的构造函数。

完美转发的实现

C++ 中的完美转发通常通过模板和 std::forward 实现。下面是一个简单的例子,演示如何通过模板函数来转发参数:

#include <utility> // for std::forward

template <typename T, typename... Args>
void construct(T& obj, Args&&... args) {
new (&obj) T(std::forward<Args>(args)...); // 使用原地构造
}

在这个例子中,construct 函数使用 std::forward 将参数 args 直接转发给 T 的构造函数。这确保了参数的类型和特性被保留,并且 T 对象会在指定的位置(由 &obj 指定)原地构造。

  • 构造函数参数转发:将函数参数直接传递给另一个构造函数,从而在目标位置直接构造对象。
  • 完美转发:确保传递的参数保持其原始特性(如左值或右值),避免不必要的复制或移动。
  • 原地构造:在已经分配好的内存区域内直接创建对象,减少了中间步骤和复制开销。

使用原地构造和构造函数参数转发可以使程序更加高效,特别是在处理复杂对象和大数据量时。

使用 emplace_back 代替 push_back

  • 性能emplace_back 可以在大多数情况下完全代替 push_back,而且在性能上通常优于 push_back。特别是当你向 vector 添加复杂对象时,emplace_back 可以避免不必要的复制或移动,减少性能开销。

  • 适用性emplace_back 更适用于需要直接在 vector 内部构造对象的情况。例如,当你要创建一个对象并将其添加到 vector 时,emplace_back 允许你直接传递构造函数参数而无需先创建临时对象。对于简单对象(如内置类型或小型 POD 类型),push_backemplace_back 的差异可能不明显,但 emplace_back 仍然是更灵活和高效的选择。

  • 兼容性emplace_back 可以用来代替 push_back,但 push_back 不能完全代替 emplace_back,因为 push_back 需要一个已经构造好的对象(或临时对象),而 emplace_back 允许在 vector 内部直接构造对象,避免了中间步骤。

结论

  • 使用 emplace_back:在可以直接构造对象的情况下,emplace_back 更优,因为它避免了不必要的复制或移动,提升性能。emplace 函数的主要任务是在这些已经分配的内部内存区域中直接构造对象
  • 使用 push_back:在需要传递已有对象时,使用 push_back 是合适的。它在添加现有对象时仍然有效。

总的来说,emplace_backpush_back 的一种更高效的选择,可以在大多数情况下完全代替 push_back。然而,根据实际情况和需求,选择合适的方法可以使代码更简洁和高效。

push_back和 emplace_back背后的逻辑的更多相关文章

  1. 3个例子详解C++ 11 中push_back 和 emplace_back差异

    本文首发于个人博客https://kezunlin.me/post/b83bc460/,欢迎阅读最新内容! cpp11 push_back and emplace_back Guide case1 # ...

  2. push_back和emplace_back的区别

    emplace_back能就地通过参数构造对象,不需要拷贝或者移动内存,相比push_back能更好地避免内存的拷贝与移动,使容器插入元素的性能得到进一步提升.在大多数情况下应该优先使用emplace ...

  3. ue4 SNew背后的逻辑

    ue4的ui库Slate体系非常庞大,即使是在创建对象这一小事上,也是相当复杂: SLATECORE_API TSharedRef<SWidget> SNullWidget::NullWi ...

  4. 当你「ping 一下」的时候,你知道它背后的逻辑吗?

    我们在遇到网络不通的情况,大家都知道去 ping 一下,看一下网络状况.那你知道「ping」命令后背的逻辑是什么吗?知道它是如何实现的吗? 一.「ping」命令的作用和原理? 简单来说,「ping」是 ...

  5. 看懂「www.google.com」背后的逻辑

    在前两篇文章中,我们完整的描述了计算机网络 OSI 五层模型的相关内容.那么,本篇将会从一个实践案例开始,带你从整体上重新认识我们的计算机网络. 我们以访问 Google 为例,当我们在浏览器地址栏中 ...

  6. Hive项目实战:用Hive分析“余额宝”躺着赚大钱背后的逻辑

    一.项目背景 前两年,支付宝推出的“余额宝”赚尽无数人的眼球,同时也吸引的大量的小额资金进入.“余额宝”把用户的散钱利息提高到了年化收益率4.0%左右,比起银行活期存储存款0.3%左右高出太多了,也正 ...

  7. 编程杂谈——使用emplace_back取代push_back

    近日在YouTube视频上看到关于vector中emplace_back与push_back区别的介绍,深感自己在现代C++中还是有不少遗漏的知识点,遂写了段代码,尝试比较两者的差别. 示例代码 #i ...

  8. emplace_back与push_back

    资料参考: https://blog.csdn.net/p942005405/article/details/84764104 实际精华在评论中,转载如下: STL的实现版本很多,VS.GCC版本不同 ...

  9. 你想知道的 std::vector::push_back 和 std::vector::emplace_back

    引言 C++ 11 后,标准库容器 std::vector 包含了成员函数 emplace 和 emplace_back.emplace 在容器指定位置插入元素,emplace_back 在容器末尾添 ...

  10. C++雾中风景9:emplace_back与可变长模板

    C++11的版本在vector容器添加了emplace_back方法,相对于原先的push_back方法能够在一定程度上提升vector容器的表现性能.所以我们从STL源码角度来切入,看看这两种方法有 ...

随机推荐

  1. OpenGL 三角形颜色插值

    1.最懒的方法--Nearest Neighbor对于三角形内的点,离三个顶点谁最近,就赋值为那个顶点对应的颜色. 2.最天真的方法--Distance三角形内一点的值应该来自于三个顶点. 计算距离: ...

  2. 前缀函数及 Knuth–Morris–Pratt 算法学习笔记

    \(\text{1 引言 Preface}\) 对于形如以下的问题: 给予一个模式串 \(T\) 和主串 \(S\),在主串中寻找 \(T\). 我们称之为字符串匹配. 很显然朴素算法时间复杂度是 \ ...

  3. freemarker+minio实现页面静态化

    什么是页面静态化? 将原本动态生成的网页内容通过某种形式转化为html并存储在服务器上,当用户请求这些页面时就不需要执行逻辑运算和数据库读 优点: 性能:提高页面加载速度和响应速度,还可以减轻数据库. ...

  4. M1 Mac安装anaconda3

    1.正常安装 首先进入官网https://www.anaconda.com/ 下载,安装 自行大胆的安装 2.环境配置 直接安装完成后,代码文件的存储路径为默认路径,为了更好的管理代码文件我们需要更换 ...

  5. keycloak~为微信二维码添加动态kc认可的动态state

    本实例将通过keycloak社区登录实现微信二维码的登录,并且二微码不是keycloak动态生成,而是通过微信提供的js生成的,在页面上直接输出的方式实现的. 动态state 在Keycloak中使用 ...

  6. python global将结果存储起来给另外一个文件对象使用

    python global将结果存储起来给另外一个文件对象使用 使用场景: 在aaa.py文件里面操作数据生成结果C 然后再在bbb.py文件里面使用C 下面是aaa.py代码: #!/usr/bin ...

  7. 【Docker】02 上手入门

    环境前提: 软硬件设备:真机 | 服务器 | 虚拟机 操作系统:Linux 协议传输工具:XSHELL等等,直接操作就不用了 网路:必须得有 Docker的安装: 还好在学Linux的时候装了一下,发 ...

  8. 凸优化: 回溯线搜索(Backtracking line search)

    声明: 本文大量摘录 https://www.cnblogs.com/kemaswill/p/3416231.html 内容. ==================================== ...

  9. 【转载】 【报错】ImportError: cannot import name 'downsample' —— lasagne模块 调用 theano 报错

    原网址: https://blog.csdn.net/kz_java/article/details/125030733 ======================================= ...

  10. 乌克兰学者的学术图谱case5

    ========================================== 背景: 弗兰采维奇材料问题研究是欧洲最大的材料科研院所,在核电.航空.航天.军工及其他装备制造领域的先进材料研制方 ...