vector中emplace_back和push_back详解,源码解读

2023-11-06

C++11之前
通常使用push_back()向容器中加入一个右值元素(临时对象)的时候,首先会调用构造函数构造这个临时对象,然后需要调用拷贝构造函数将这个临时对象放入容器中。原来的临时变量释放。这样造成的问题是临时变量申请的资源就浪费。
C++11之后
引入了右值引用,转移构造函数后,push_back()右值时就会调用构造函数和转移构造函数。

emplace_back
源码:主要看有注释的地方,通过完美转发,最终到构造对象,找到对应的构造函数进行构造

	template<class... _Valty>
	// 可以看出传入的时完美转发的参数
		decltype(auto) emplace_back(_Valty&&... _Val)
		{	// insert by perfectly forwarding into element at end, provide strong guarantee
		if (_Has_unused_capacity())
			{
			return (_Emplace_back_with_unused_capacity(_STD forward<_Valty>(_Val)...));
			}
//在调用重新构造时,将参数再完美转发出去
		_Ty& _Result = *_Emplace_reallocate(this->_Mylast(), _STD forward<_Valty>(_Val)...);
#if _HAS_CXX17
		return (_Result);
#else /* ^^^ _HAS_CXX17 ^^^ // vvv !_HAS_CXX17 vvv */
		(void)_Result;
#endif /* _HAS_CXX17 */
		}

template<class... _Valty>
		pointer _Emplace_reallocate(const pointer _Whereptr, _Valty&&... _Val)
		{	// reallocate and insert by perfectly forwarding _Val at _Whereptr
			// pre: !_Has_unused_capacity()
		const size_type _Whereoff = static_cast<size_type>(_Whereptr - this->_Myfirst());
		_Alty& _Al = this->_Getal();
		const size_type _Oldsize = size();

		if (_Oldsize == max_size())
			{
			_Xlength();
			}

		const size_type _Newsize = _Oldsize + 1;
		const size_type _Newcapacity = _Calculate_growth(_Newsize);

		const pointer _Newvec = _Al.allocate(_Newcapacity);
		const pointer _Constructed_last = _Newvec + _Whereoff + 1;
		pointer _Constructed_first = _Constructed_last;

		_TRY_BEGIN
		// 接收完美转发后的参数,根据参数构造对象
		_Alty_traits::construct(_Al, _Unfancy(_Newvec + _Whereoff), _STD forward<_Valty>(_Val)...);
		_Constructed_first = _Newvec + _Whereoff;

		if (_Whereptr == this->_Mylast())
			{	// at back, provide strong guarantee
			_Umove_if_noexcept(this->_Myfirst(), this->_Mylast(), _Newvec);
			}
		else
			{	// provide basic guarantee
			_Umove(this->_Myfirst(), _Whereptr, _Newvec);
			_Constructed_first = _Newvec;
			_Umove(_Whereptr, this->_Mylast(), _Newvec + _Whereoff + 1);
			}
		_CATCH_ALL
		_Destroy(_Constructed_first, _Constructed_last);
		_Al.deallocate(_Newvec, _Newcapacity);
		_RERAISE;
		_CATCH_END

		_Change_array(_Newvec, _Newsize, _Newcapacity);
		return (this->_Myfirst() + _Whereoff);
		}

	template<class _Objty,
		class... _Types>
		static void construct(_Alloc&, _Objty * const _Ptr, _Types&&... _Args)
		{	// construct _Objty(_Types...) at _Ptr
		//最终传入的参数类型在这里使用,根据完美转发规则,传入的时什么类型参数,然后匹配其对象对应的构造函数进行对象构造。如果是一系列参数,就调用自定义的构造函数,如果是左值,就调用拷贝构造,如果是右值,就调用移动构造。若没有移动构造,就调用拷贝构造
		::new (const_cast<void *>(static_cast<const volatile void *>(_Ptr)))
			_Objty(_STD forward<_Types>(_Args)...);
		}

结论:

  • 对于传入的是对象构造参数(右值),empalce_pack内部是使用的完美转发,在构造对象时是进行原地构造,直接调用对象的构造函数进行构造,并存入容器中,减少push_back的临时对象构造和析构过程。
  • 对于传入的是对象(左值),empalce_pack内部是使用的完美转发,在构造对象时调用其拷贝构造函数进行构造并存入容器中
  • 对于传入的时对象右值(类似std::move()转换后的对象),empalce_pack内部是使用的完美转发,在构造对象时调用其移动构造函数进行构造并存入容器中。若没有移动构造,则调用拷贝构造创建对象并存入容器中。

push_back

//可以看到,里面都是调用的emplace_back函数
void push_back(const _Ty& _Val)
		{	// insert element at end, provide strong guarantee
		emplace_back(_Val);
		}

	void push_back(_Ty&& _Val)
		{	// insert by moving into element at end, provide strong guarantee
		emplace_back(_STD move(_Val));
		}

结论:

  • 传入的是左值,根据emplace_back的完美转发原则,会调用拷贝构造函数进行元素添加
  • 传入的是右值,同理根据完美转发原则,会调用移动构造函数进行构造,如果没有移动构造,则调用拷贝构造函数进行构造,并进行元素添加

代码测试:

#include <iostream>
#include <vector>
#include <string>
struct Persion
{
  std::string name;
  std::string country;
  int year;

  Persion(std::string p_name, std::string p_country, int p_year)
    : name(std::move(p_name)), country(std::move(p_country)), year(p_year)
  {
    std::cout << "I am being constructed.\n";
  }
  Persion(const Persion& other)
    : name(std::move(other.name)), country(std::move(other.country)), year(other.year)
  {
    std::cout << "I am being copy constructed.\n";
  }
  Persion(Persion&& other)
    : name(std::move(other.name)), country(std::move(other.country)), year(other.year)
  {
    std::cout << "I am being moved.\n";
  }
  Persion& operator=(const Persion& other);
};

int main() {
  std::vector<Persion> elections;
  std::cout << "emplace_back:\n";
  elections.emplace_back("person1", "South Africa", 1991); //没有类的创建  

  std::vector<Persion> reElections;
  std::cout << "\npush_back:\n";
  Persion test("person12", "the USA", 1992);
  reElections.push_back(test);
  reElections.push_back(std::move(test));
  system("pause");
  return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vector中emplace_back和push_back详解,源码解读 的相关文章

  • 在Windows 7上安装curl后缺少libcurl-4.dll

    按照这个人的安装curl后指示 https stackoverflow com a 28757477 1186038 除了第 2 步 已安装Win64 OpenSSL v1 0 1u 轻型相反 因为下载页面中缺少版本 k http slpr
  • 在 Visual Studio C++ 2008 中包含 dll

    有没有办法将 dll 包含在项目中 这样我就不必在编译后将这些 dll 与可执行文件放在同一文件夹中 这样我就可以用它们编译我的项目 这是否有可能 如果是 有人可以指导我 我的项目是一个 opencv 项目 有很多 dll 我必须包含在文件
  • 在生产数据库上部署应用程序时无法加载文件或程序集“System.Data”错误

    问题 将我的应用程序部署到生产数据库时 出现以下错误 无法加载文件或程序集 System Data Version 2 0 0 0 Culture neutral PublicKeyToken b77a5c561934e089 或其依赖项之
  • “你好,TensorFlow!”使用 C API

    出于学习目的 如何使用 TensorFlow C API 编写此 Python 示例 import tensorflow as tf hello tf constant hello TensorFlow sess tf Session pr
  • 获取进程的所有 DLL

    我想获取为给定进程加载的所有 dll 的列表 我目前正在使用 NET框架4 0 我知道有一个bug https connect microsoft com VisualStudio feedback details 546430 syste
  • 如何将 NLog 用于 DLL

    我正在尝试使用 Nlog Refresh 1 0 为类库项目实现一个简单的日志 当 nlog 从 dll 中实例化时 它似乎不会创建日志文件 还有其他办法解决这个问题吗 我的配置文件如下所示
  • 在 C++ 项目中放置 dll 文件以及如何包含这些文件?

    我读了这个guide http nil techno blogspot co il 2009 10 creating visual studio 2008 application html它将引导您完成使用 Cairo 和 Visual C
  • 在Framework 4.6项目中使用.net core DLL

    我已经在 net core 2 0 中构建了一个 DLL 现在我想在使用 net 4 6 1 框架的 WinForms 项目中使用它 我可以引用该 dll 但收到 System IO FileLoadException 表示找不到 Syst
  • RegAsm regfile 开关没有提供与代码库开关相同的输出

    好吧 我知道这是非常具体的 但我为此浪费了整个工作日 所以我真的需要一些合理的解释 这样我的老板和我的妻子就不会解雇我 根据 MSDN The regfile开关 为程序集生成指定的 reg 文件 The codebase开关 在注册表中创
  • 使用 C++ 程序中的 dll。 (borland c++ builder 和一般情况)

    我试图在我的程序中使用一个 dll 即 libcurl 但是它没有链接 Libcurl 附带了我可以包含的 h 文件 负责 dllimport 但我想我必须指定在以某种方式链接时实际使用哪个 dll 我该怎么做 我正在使用 Borland
  • 我想在 VB6 程序中使用 VB.NET dll。是否可以?

    我在 VB6 程序中使用 VB NET dll 时遇到问题 我已经使用 GuidAttribute 创建了 dll 使用 RegAsm 创建了 tlb 并将其添加到我的 VB6 程序的引用中 问题是当我尝试使用 CreateObject 函
  • System.MissingMethodException:找不到方法?

    以前工作的 ASP NET WebForms 应用程序现在抛出此错误 System MissingMethodException 找不到方法 The DoThis方法位于同一个类上 它应该可以工作 我有一个这样的通用处理程序 public
  • 如何在Electron App中调用C# dll方法?

    我有一个电子应用程序 可以从读卡器读取信用卡详细信息 他们提供了一个 c dll 来与应用程序交互 我不知道如何从电子应用程序读取 dll 方法 首先使用以下命令检查 dll 中公开的函数依赖步行者 http www dependencyw
  • 在 Windows 安装项目中注册和取消注册 DLL

    我有几个 dll 文件需要在安装 卸载 Windows 安装程序时分别注册 取消注册 我尝试了以下方法 创建一个 bat 文件来注册 dll 问题是我无法在安装项目中使用 自定义操作 添加 bat 文件 另外 如何在卸载时运行注销dll 请
  • 如何使用 C# 和 .NET 中的 C++ 库?

    我的问题与 DLL 如何导出 C 类和泛型方法 关于没有 C 并行的 C 语言功能 密切相关 我相信你可以在extern C 只需引用 DLL 并使用 DLLImport 即可从 C 中阻止 但是您可以实例化模板化的 C 类型吗 如果 C
  • 使用 xerces 链接 DLL 会给出未定义的符号

    我正在使用 cygwin 创建一个共享库 DLL 它使用 Xerces 当我从主应用程序调用 xercesc 函数时 一切都很好 但是当我尝试将一些代码放入库中时 我会得到 xerxesc 定义的所有静态内容的未定义符号 例如 std st
  • 来自外部 DLL 的未处理的 DivideByZero 异常 - C#

    我有一个 C net 4 0 程序 其主要功能是从外部 FTP 库 项目引用的 dll 调用方法 逻辑位于 try catch 块中 catch 会打印错误 异常处理程序有一个通用参数 catch Exception ex IDE是VS 有
  • 使用 PIMPL 习惯用法删除 DLL 中的 std::vector 时出错

    我有以下代码 In DLL1 在 h文件中 class MyClass public MyClass private std string m name class declspec dllexport Foo private struct
  • ctypes 加载 dll 时没有错误消息,但什么也没发生

    我尝试在ctypes中使用windll LoadLibrary将dll文件导入python 尽管没有任何错误消息 但头文件中列出的函数似乎都没有成功加载 我想知道是dll文件有问题 还是我错误地使用了windll LoadLibrary方法
  • 如何从本机 C(++) DLL 调用 .NET (C#) 代码?

    我有一个 C app exe 和一个 C my dll my dll NET 项目链接到本机 C DLL mynat dll 外部 C DLL 接口 并且从 C 调用 C DLL 可以正常工作 通过使用 DllImport mynat dl

随机推荐

  • 在线沙箱网站 在线恶意文件监测网站 病毒在线监测网站 apk分析在线网站

    沙箱 https www joesandbox com windows 沙箱 VirSCAN https www virscan org language de 只能传20M以内的文件 VirusTotal https www virust
  • 【注释模板】IDEA中JAVA类、方法注释模板教程

    文章目录 TOC 1 引言 2 JAVA创建类时注释模板配置 2 1 打开IDEA 依次点击File gt Setting 2 2 在Settings界面中依次点击Editor gt File and Code Templates 并在Fi
  • 关于示波器产生奇特波形的解释

    转发 https blog csdn net y511374875 article details 80583585
  • 让机器“看山是山”:脑启发的视觉计算

    编者按 人生之三境界的第一层 看山是山 看水是水 本质上展示了人 看见 的过程 以及思绪与理解在这一过程中所起的作用 看见 对于人类而言 似乎是一个很简单自然的事情 其实则不然 从地球上第一个长出眼睛的生物三叶虫 走到今天的人类视觉 经历了
  • office365 无法登录_office365、office2019微软账号无法登录如何解决?

    我相信很多人肯定被这个问题折磨得头大 因为微软服务器在国外的原因 所以部分设备很难登入 但是OneNote Office365 Ofice等软件如果是绑定了微软账号的 需要登入微软账号才可以激活和保存数据 日常帮助很多订阅客户处理过这个问题
  • 【数据结构】循环队列的实现(附带详细注释)

    前言 数据结构系列首页 是数据结构系列文章的首页 其中会逐步更新各种数据结构的实现 有兴趣的选手可以一看 首页中不仅有各种数据结构的实现 还有学习数据结构必备的基础知识 如果有选手觉得自己的基础不太牢固 可以先将搞定基础知识 之后再攻克数据
  • 剑指 Offer 68 - I. 二叉搜索树的最近公共祖先 -- 递归

    0 题目描述 leetcode原题链接 剑指 Offer 68 I 二叉搜索树的最近公共祖先 1 递归解法 终止条件 当 root 为空时 返回 None 当 p q 都在 root 的右子树中 则开启递归 root right 并返回 否
  • 企业大数据CDH集群安全----sentry

    Sentry安装 1 cm中选择添加服务 选择sentry 2 选择要安装sentry的主机 3 配置数据库 HDFS配置 开启启动访问控制列表 选中打勾 开启检查HDFS权限服务 开启sentry服务 hive配置 修改hive配置参数
  • 获取IronSource的广告源Pod和Maven版本

    接入IronSource库后 现在可以选择Maven或者Pod的形式导入相关广告源 Ironsource官网上有一个入口 可以方便的获取接入广告源的Maven和Pod Android https developers ironsrc com
  • Object.keys()、Object.values()、Object.entries()的用法

    一 Object keys obj 参数 要返回其枚举自身属性的对象 返回值 一个表示给定对象的所有可枚举属性的字符串数组 处理对象 返回可枚举的属性数组 let person name 张三 age 25 address 深圳 getNa
  • java参数校验常见注解介绍

    一 NotEmpty NotBlank NotNull区别介绍 NotEmpty 常用于集合 字符串等 不能为空 且长度必须大于0 NotBlank 用于字符串上 不能为空 且长度必须大于0 NotNull 字面意思 一般用于基本类型 不为
  • 聊聊编程是什么

    前言 前言不看没关系 不影响 半夜睡不着 想写点啥 浅聊下我理解的编程的 我认为编程就是解决问题 就像互联网是依附于实体业 是处理解决实际问题的 刚学编程的时候总是很恐慌的 天赋不够 我这么认为的原因 一是当时流行一种说法叫不是热爱编程的是
  • Mongodb数据库的安装部署及基本使用

    Mongodb数据库的安装部署及基本使用 一 Mongodb数据库介绍 1 Mongodb简介 2 Mongodb适用场景 3 MongoDB特性 二 检查本地系统环境 1 检查系统版本 2 检查yum仓库 三 Mongodb的安装 1 配
  • 【python开发】1. __init__.py与导包

    python开发 开始拿着github上的python代码狂啃时 发现很多知道干嘛又不知道为啥这样的代码 开始疯狂补漏 package 导包 用处1 导入包 比如这样的架构 package1 subPack1 init py module
  • 爬虫豆瓣top250

    爬虫豆瓣top250 前言 一 爬虫是什么 二 爬取豆瓣的原因 三 爬虫项目步骤 1 准备工具 2 学习python的相关知识 3 爬虫过程讲析 四 成果展示 五 代码展示 前言 随着网络的迅速发展 万维网成为大量信息的载体 如何有效地提取
  • 深度学习理论_卷积神经网络

    1 要点 激活函数一般用于卷积层和全连接层之后 激活函数是深度网络非线性的主要来源 常见的激活函数Sigmoid 双曲正切 ReLU 生物启发 克服了梯度消失问题 PReLU alpha可学习 ELU和maxout 其中PReLU和ELU都
  • MQClientException: CODE: 208  DESC: query message by key finished, but no message.

    2019 05 15 10 19 31 401 INFO closeChannel close the connection to remote address 127 0 0 1 10911 result true 2019 05 15
  • lua的for循环

    lua的三种for循环介绍 本文的lua代码编辑于luaforwindows 1 数值for循环 如图 举例如下 2 ipairs迭代器 举例如下 说明 ipairs按照索引值顺序 打印出了table中有索引值的数据 没有索引值的不管 3
  • 自定义mvc原理和框架实现

    目录 1 什么是MVC 2 自定义MVC工作原理图 3 自定义mvc的简单实现 1 中央控制器 2 Action接口定义 3 实现子控制器 4 完善中央控制器 1 请求分发功能 2 使用配置文件配置action 3 请求参数处理 4 完善A
  • vector中emplace_back和push_back详解,源码解读

    C 11之前 通常使用push back 向容器中加入一个右值元素 临时对象 的时候 首先会调用构造函数构造这个临时对象 然后需要调用拷贝构造函数将这个临时对象放入容器中 原来的临时变量释放 这样造成的问题是临时变量申请的资源就浪费 C 1