[C++] push_back和emplace_back的区别

11 篇文章 0 订阅
订阅专栏

一、vector容器内存的特点

先介绍vector的内存特点,vector为了支持快速的随机访问,vector容器内元素以连续的方式存放,而为了提高在添加元素时的性能,vector允许在创建时额外预留一些多出来的储存空间,为添加新元素做准备。

vector的元素并未存在vector地址最开始处,而是在后续一段地址,即vector.data()所指的地址才开始存放元素。个人猜测从&vector到vector.data()这段内存中,应该存放了这个vector的一些信息,比如说长度、容量等。

cout << "创建一个空的容器person" << endl;
vector<Person> person;

cout << "扩容这个空的容器" << endl;
person.reserve(2);

cout << "容器的大小:" << person.size()<<endl;

cout << "容器的容量:" << person.capacity() << endl;

cout << "容器的地址:" << &person << endl;

cout << "容器的第一个元素的地址:" << person.data() << endl;

在这里插入图片描述

在上述代码后,容器person的内存空间如下图所示:
在这里插入图片描述

二、测试类

class Person {
public:
	// 无参构造
	Person() {

	}
	// 有参构造
	Person(int age) : _age(age) {
		cout << "调用有参构造,构造一个对象 "<< endl;
		cout << "构造的这个对象所在的地址:" << this << endl;
	}
	// 拷贝构造
	Person(const Person& p) : _age(p._age) {
		cout << "调用拷贝构造,构造一个对象 "<< endl;
		cout << "被拷贝的对象所在地址:" << &p << endl;
		cout << "构造的这个对象所在的地址:" << this << endl;
	}
	// 右值构造
	Person(const Person&& p) : _age(p._age) {
		cout << "调用右值构造,构造一个对象:" << _age << endl;
		cout << "所传进来的右值所指代的空间的地址:" << &p << endl;
		cout << "构造的这个对象所在的地址:" << this << endl;
	}
	// 析构
	~Person() {
		cout << "析构" << _age << endl;
	}
public:
	int _age;
};

有参构造函数传入的是对象的参数,用以赋予到创建的对象的属性上

拷贝构造函数传入的是已有对象的地址,用以拷贝

右值构造函数传入的是右值,指示一块没有名字的内存空间,同样用以拷贝

三、push_back()

1、push_back(实体对象)

首先使用测试类的有参构造函数,构造一个实体对象 p1 :

cout << "创建一个对象" << endl;
Person p1 = Person(10);

在这里插入图片描述

申请了一块内存空间存放实体对象p1,这时内存空间如下图:
在这里插入图片描述

cout << "现在开始push_back" << endl;
person.push_back(p1);

cout << "容器的地址:" << &person<< endl;
cout << "容器的第一个元素的地址:" << &person[0] << endl;
cout << "这时容器内的第一个元素是:" << person[0]._age<< endl;
cout << endl;

在这里插入图片描述

从输出中可以看出,push_back(实体对象)时,会把实体对象的地址&p1传入测试类中,调用测试类的拷贝构造函数(该构造函数的输入是一个地址值),在容器内存中元素所在储存的末尾,构造一个新的对象。通过传入的实体对象的地址&p1,将这个实体对象内的数据拷贝进新创建的对象中,完成添加操作。
在这里插入图片描述

这时并没有调用析构函数,也就是说原有的实体对象p1仍存在。
在这里插入图片描述

2、push_back(参数)

重新弄一个新的容器:
在这里插入图片描述

在这里插入图片描述
如果在push_back()函数内直接传入一个参数:

cout << "现在开始push_back参数10" << endl;
person.push_back(10);

cout << "容器的地址:" << &person << endl;
cout << "容器的第一个元素的地址:" << &person[0] << endl;
cout << "这时容器内的第一个元素是:" << person[0]._age << endl;
cout << endl;

在这里插入图片描述
从输出可以看出,push_back(参数)时,会首先调用测试类的有参构造函数,创建一个临时对象,然后再将这个临时对象所在的内存空间的地址作为右值传入测试类的右值构造函数中,测试类的右值构造会在容器内存中元素所在储存空间的末尾,创建一个新的对象,并通过地址,到临时对象所在的内存空间中,将里面的数据拷贝进新的对象里,完成添加操作。

最后,临时对象的析构函数会被调用,这个对象将被析构,不再存在。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

3、push_back( move(实体对象) )

在这里插入图片描述
在这里插入图片描述
首先,创造一个实体对象

Person p1 = Person(10);

在这里插入图片描述
在这里插入图片描述
将实体对象 p1 经过move() 函数转成右值之后,传入push_back()函数中

cout << "现在开始push_back右值move(p1)" << endl;
person.push_back(move(p1));

cout << "容器的地址:" << &person << endl;
cout << "容器的第一个元素的地址:" << &person[0] << endl;
cout << "这时容器内的第一个元素是:" << person[0]._age << endl;
cout << endl;

在这里插入图片描述
从输出可以看出,move()将实体对象所在内存空间的地址转化成了右值,因此在push_back时便会调用测试类的右值构造函数,在容器的末尾创建一个新的对象,并去到右值所指示的内存空间中,将里面的数据拷贝到新对象上。

与同样会调用测试类的右值构造函数的push_back(参数)的区别在于,push_back( move(实体对象) )在完成数据的拷贝后,不会调用析构函数析构右值所指示的那部分内存空间,也就是说,实体对象 p1 仍然存在,且指针 p1 所指示的内存空间内的值没有变化,仍然可以被访问。

cout << "实体对象p1仍存在,地址:" << &p1 << endl;
cout << "p1所指处的地址内仍有数据:" << p1._age << endl;

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、emplac_back()

1、emplace_back(实体对象)

cout << "创建一个空的容器person" << endl;
vector<Person> person;

cout << "扩容这个空的容器" << endl;
person.reserve(2);

cout << "容器的大小:" << person.size()<<endl;

cout << "容器的容量:" << person.capacity() << endl;

cout << "容器的地址:" << &person << endl;

cout << "容器的第一个元素的地址:" << person.data() << endl << endl << endl;

cout << "创建一个对象" << endl;

Person p1 = Person(10);

cout << endl << endl << endl;

cout << "现在开始emplace_back实体对象p1" << endl;
person.emplace_back(p1);

cout << endl << endl << endl;

cout << "容器的地址:" << &person << endl;
cout << "容器的第一个元素的地址:" << &person[0] << endl;
cout << "这时容器内的第一个元素是:" << person[0]._age << endl;
cout << endl;

在这里插入图片描述
从输出中可以看出,emplace_back(实体对象),会调用测试类的拷贝构造函数,在容器末尾创建一个新的对象,并把实体对象p1的地址作为参数传入拷贝构造函数中,拷贝构造函数到达地址所指示的内存空间,将里面的数据拷贝到新创建的对象内,完成添加操作。

操作完成后,同样没有析构函数被调用,也就是说原有实体对象 p1 仍然存在。

在这里插入图片描述

2、emplace_back(参数)

cout << "创建一个空的容器person" << endl;
vector<Person> person;

cout << "扩容这个空的容器" << endl;
person.reserve(2);

cout << "容器的大小:" << person.size()<<endl;

cout << "容器的容量:" << person.capacity() << endl;

cout << "容器的地址:" << &person << endl;

cout << "容器的第一个元素的地址:" << person.data() << endl << endl << endl;
	
cout << endl << endl << endl;

cout << "现在开始emplace_back参数" << endl;
person.emplace_back(10);

cout << endl << endl << endl;

cout << "容器的地址:" << &person << endl;
cout << "容器的第一个元素的地址:" << &person[0] << endl;
cout << "这时容器内的第一个元素是:" << person[0]._age << endl;
cout << endl;

在这里插入图片描述
当使用emplace_back(10)的时候,从输出中就可以明显看出与push_back(10)的差别了。

emplace_back(10)并没有创建临时对象,最后析构临时对象的操作。而是调用测试类的有参构造函数,在容器的末尾直接创建一个新的对象,这时就完成添加操作了。

在这里插入图片描述
由于没有创建临时对象、拷贝、析构的操作,也就是没有通过临时对象中转,性能自然比push_back(10)要好。

3、emplace_back( move(实体对象) )

cout << "创建一个空的容器person" << endl;
vector<Person> person;

cout << "扩容这个空的容器" << endl;
person.reserve(2);

cout << "容器的大小:" << person.size()<<endl;

cout << "容器的容量:" << person.capacity() << endl;

cout << "容器的地址:" << &person << endl;

cout << "容器的第一个元素的地址:" << person.data() << endl << endl << endl;

cout << "创建一个对象" << endl;

Person p1 = Person(10);

cout << endl << endl << endl;

cout << "现在开始emplace_back( move(实体对象) )" << endl;
person.emplace_back(move(p1));

cout << endl << endl << endl;

cout << "容器的地址:" << &person << endl;
cout << "容器的第一个元素的地址:" << &person[0] << endl;
cout << "这时容器内的第一个元素是:" << person[0]._age << endl;
cout << endl;

cout << "实体对象p1仍存在,地址:" << &p1 << endl;
cout << "p1所指处的地址内仍有数据:" << p1._age << endl;

在这里插入图片描述
与push_back( move(实体对象) )没有区别,就不细说了。

五、总结

push_back和emplace_back的区别只在传入的参数是对象的构造参数时,如push_back(10),emplace_back(10)。

两种情况下:
push_back(10)会先调用类的有参构造函数,创建一个临时对象,再在容器的末尾调用类的右值构造函数(因为这个临时对象没有名字,属于右值,所以只能使用右值构造函数),输入临时对象的地址,创建一个新的对象,根据地址值到临时对象所在的内存空间中拷贝数据,最后再调用临时对象的析构函数,析构这个临时对象。

emplace_back(10)少了临时对象这一步,直接在容器的末尾调用类的有参构造函数创建一个新的对象,完成添加操作。

C++ emplace_back 与 push_back
m0_73935863的博客
03-03 1571
C++ emplace_back 与 push_back
栈堆的emplacepush_C++姿势点: push_back和emplace_back
weixin_39618275的博客
01-17 394
网上最常讲的:C++ vector::push_back 会先创建临时对象,然后将临时对象拷贝到容器中,最后销毁临时对象;但是 emplace_back 仅会在容器中原地创建一个对象出来,减少临时对象拷贝、销毁的步骤,所以性能更高。我查阅资料后,觉得这个说法不全面,容易引起误导。所以将自己学到的做个记录,帮助新晋c++程序员消疑。差异1:如果插入vector的 类型 的 构造函数 接受多个参数,那...
c++ push_back与emplace_back
qq_33766994的博客
04-15 1135
push_back与emplace_back 本节直接讨论在向容器添加数据时,插入(push_back、push_front、insert等)和置入(emplace_back)的内存性能情况,深入了解C++的内部机制。考虑下面代码: vector<string> vs; vs.push_back("abcd"); push_back的两个版本: void push_back(const T& x);//左值 void push_back(T&& x);//右值 vs是
emplace_back和push_back超详细讲解+常见问题分析[more cpp-5]
最新发布
FlamBoyanceI的博客
08-25 444
这两个函数都是在容器的尾部插入对象,不过push_back是早期的函数(为CPP98,就是第一个CPP标准化版本),emplace_back则是在CPP11加入的重要特性,是CPP高性能化的重要特征。简单的来说 - push_back是传入一个对象,而后在容器的尾部拷贝一个出来 - emplace_back是传入构造对象的参数,然后直接在**对象尾部直接构造出来这个对象**
C++push_back()和emplace_back()区别
qq_41605662的博客
11-23 1473
C++push_back()和emplace_back()区别
c++ emplace_back与push_back
playerz的博客
02-01 580
容器的emplace_back与push_back方法 emplace_back针对添加的元素为 “某个对象struct、class” ,可以直接写参数,函数自动调用构造函数,而不用先创建对象再添加。 push_back需要先创建对象,再添加。 emplaceemplace_front类似 #include<iostream> #include<vector> #in...
C++emplace_back 和 push_back(含相应的 C++ 代码)
m0_51913750的博客
06-01 1168
C++emplace_back 和 push_back
C++ 中”emplace_back” 与 “push_back” 的区别
01-01
C++ 中”emplace_back” 与 “push_back” 的区别 emplace_back和push_back都是向容器内添加数据. 对于在容器中添加类的对象时, 相比于push_back,emplace_back可以避免额外类的复制和移动操作. “emplace_back ...
c++push_back 以及 emplace_back 的区别
01-20
C++编程中,`push_back` 和 `emplace_back` 是两种向标准库容器(如 `std::vector`)添加元素的方法,它们之间的主要区别在于元素构造的方式和效率。这里我们将详细探讨这两种方法的工作原理,并结合提供的代码...
C++小实验之vector的 push_back 和 emplace_back 及其使用时机
xmz782429852的博客
09-04 705
参考 参考一: 如果参数是左值,两个调用的都是copy constructor 如果参数是右值,两个调用的都是move constructor(C++ 11后push_back也支持右值) 最主要的区别是,emplace_back支持in-place construction,也就是说emplace_back(10, “test”)可以只调用一次constructor,而push_back(MyClass(10, “test”))必须多一次构造和析构 ———————————————— 版权声明:本文为C
C++性能优化秘籍:emplace_back() vs push_back()
m0_72877724的博客
07-14 1205
C++中,向容器添加元素是一个常见的操作。STL容器(如vector、list、deque等)提供了两种主要的方法来在末尾添加元素:push_back() 和 emplace_back()。虽然它们的目的相似,但在实现和性能上有着显著的区别。让我们深入了解这两个函数,看看如何优化你的代码。
c++中的emplace_back 与push_back
追赶时代的博客
05-23 367
emplace_back push_back
c++11 之emplace_back 与 push_back的区别
热门推荐
学之知之的博客
12-03 16万+
c++开发中我们会经常用到插入操作对stl的各种容器进行操作,比如vector,map,set等。在引入右值引用,转移构造函数,转移复制运算符之前,通常使用push_back()向容器中加入一个右值元素(临时对象)时,首先会调用构造函数构造这个临时对象,然后需要调用拷贝构造函数将这个临时对象放入容器中。原来的临时变量释放。这样造成的问题就是临时变量申请资源的浪费。 引入了右值引用,转移构造函数后...
【C/C++ 容器操作】C++高效编程:掌握emplace_back与push_back的使用和机制
探索C++编程的奥秘,分享深入的技术见解和实践,旨在激发读者创造力与解决问题的思维。
02-17 1522
在现代软件开发的世界里,C++一直是性能敏感型应用的首选语言。它提供了强大的类型系统、内存管理能力和丰富的标准库,其中容器的使用更是C++编程中不可或缺的一部分。容器不仅仅是数据的集合,它们还代表了数据结构和算法设计的基石。在C++的标准模板库(STL)中,容器如`vector`、`list`、`deque`等,提供了多种数据插入的方法,其中`push_back`和`emplace_back`因其使用的便捷性和效率差异而受到开发者的特别关注。
C++emplace_back 和 push_back
mls805379973的博客
03-12 400
直接在容器内构造元素。选择使用哪种方式取决于你的需求和性能考虑。通常来说,如果你需要直接在容器中构造元素,并且有可能带来性能优势,那么使用。都是用于将元素添加到容器的操作,但它们之间有一些关键的区别。需要调用移动构造函数,而。
C++ 容器 push_back 和 emplace_back
qq_42303573的博客
12-28 2279
C++ 容器 push_back 和 emplace_back
push_back 和 emplace_back 的区别
明朗晨光的专栏
07-25 2814
C++ 中 vector 的 push_back 和 emplace_back 的区别
一篇文章搞懂 push_back 和 emplace_back 的区别
qq_37124218的博客
09-23 5256
全文从源码角度剖析 push_back 和 emplace_back 的区别,并用生动形象的例子来展示其微妙的区别
C++ push_back和emplace_back的区别
08-30
`push_back`和`emplace_back`是C++中用于向容器尾部添加元素的两个函数。 1. `push_back`函数将一个已经存在的对象副本(或者是右值引用)添加到容器尾部。它会调用对象的拷贝构造函数或移动构造函数。 2. `...
写文章

热门文章

  • [OpenGL] 视图矩阵(View)矩阵与glm::lookAt函数源码解析 9317
  • [OpenGL] VAO、VBO、EBO 4957
  • 三维点云配准 4577
  • [C++] Kmeans算法实现 3796
  • [三维重建] [机器学习] 图片相似度 3659

分类专栏

  • OpenGL 4篇
  • 三维重建 5篇
  • C++ 11篇
  • 计算机组成原理 1篇
  • 计算机网络 1篇
  • 操作系统 3篇
  • 机器学习 5篇
  • MIT 6.006 算法导论 2篇

最新评论

  • [计算机组成原理] 指令的完成过程

    重生之我在编程当大佬: 存数指令的步骤8应该是:ACC的内容存到MDR

  • [计算机组成原理] 指令的完成过程

    是piggy啦: 写的我一下子就看懂了表情包表情包

  • [OpenGL] VAO、VBO、EBO

    玉带湖水位记录员: 图都是copy的

  • [OpenGL] VAO、VBO、EBO

    玉带湖水位记录员: 基本跟learnopengl说的一样

  • 自编码器处理数据

    完美主义的鲸鱼: 转成tensor直接输入网络

大家在看

  • 【系统规划与管理师】历年各章节分值汇总(论文)
  • PTA7-16幸运彩票 45
  • Vue2 项目实战:打造一个简易倒计时计时器工具 Vue2 实践教程:如何实现一个工作与休息倒计时工具 从零开始:使用 Vue2 构建你的倒计时计时器 初学者友好:Vue2 实现简单倒计时应用,附完整
  • 矩阵对角化 405
  • 数据流风格 370

最新文章

  • [深度学习] SpaceToDepth 类
  • [深度学习] labels2Dto3D 函数
  • [深度学习] magic point
2022年33篇
2021年8篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

玻璃钢生产厂家开远市玻璃钢雕塑厂家电话亳州动物玻璃钢雕塑安装玻璃钢公园雕塑垃圾桶濮阳玻璃钢雕塑加工厂唐山动物玻璃钢雕塑生产厂家工业玻璃钢雕塑服务介绍临沧市玻璃钢雕塑加盟商亳州学校玻璃钢雕塑人物玻璃钢雕塑怎么样长征红军玻璃钢雕塑陆丰玻璃钢伟人像雕塑江苏商场创意商业美陈服务商场气球美陈教程玻璃钢花盆到哪里批发河东玻璃钢动物雕塑公仔玻璃钢人物雕塑参考价玻璃钢雕塑常见造型无锡商场户外美陈金昌玻璃钢动物雕塑多少钱公园摆件玻璃钢雕塑电话多少济南步行街玻璃钢雕塑价位南阳园林景观玻璃钢仿铜雕塑雕塑无机玻璃钢与砂石哪个好宁夏玻璃钢雕塑定做水景池玻璃钢雕塑浮雕玻璃钢雕塑制作商场美陈亮化定制工厂深圳大型商场美陈销售玻璃钢雕塑是怎么上金粉吴川玻璃钢牌匾雕塑香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化