push_back和emplace_back比较以及vector扩容


关于这部分内容,也是C++中的老生常谈的问题了,一些最基本的介绍这边也就不再进行了,着重对比一下两者的使用情况,然后再给出结论。

C++中push_back和emplace_back的区别

push_back和emplace_back的比较

使用测试类

class Person {
public:
	// 无参构造
	Person() {
	
	}
	// 有参构造
	Person(int age) : _age(age) {
		cout << "Construct a class: " << _age << endl;
	}
	// 拷贝构造
	Person(const Person& p) : _age(p._age) {
		cout << "Copy Construct a class: " << _age << endl;
	}
	// 转移构造
	Person(const Person&& p) : _age(p._age) {
		cout << "Move Construct a class: " << _age << endl;
	}
	// 析构
	~Person() {
		cout << "Destory a class: " << _age << endl;
	}
private:
	int _age;
};

测试过程

将实体类对象传入

如下代码所示,直接传入已经实体类对象,比较两者差异。

int main(int argc, char** argv) {
	cout << "push_back demo: " << endl;
	vector<Person> person1;
	Person p1 = Person(10);
	cout << "Now start push_back" << endl;
	person1.push_back(p1);

	cout << endl;

	cout << "emplace_back demo: " << endl;
	vector<Person> person2;
	Person p2 = Person(20);
	cout << "Now start emplace_back" << endl;
	person2.emplace_back(p2);

	system("pause");
	return 0;
}

测试结果:
在这里插入图片描述
结论1:

  • push_back:首先会调用构造函数创建出一个实体类对象p1,然后调用拷贝构造函数,将这个实体类对象传给push_back()这个函数中;
  • emplace_back:首先会调用构造函数创建出一个实体类对象p2,然后调用拷贝构造函数,将这个实体类对象传给emplace_back()这个函数中;
  • 如果直接传入实体类对象的话,先构造出这个对象,然后调用拷贝构造函数将这个对象传递给xxx_back()这个函数,最后插入到容器中;
     

将右值数字传入

int main(int argc, char** argv) {
	cout << "push_back demo: " << endl;
	vector<Person> person1;
	cout << "Now start push_back" << endl;
	person1.push_back(12);

	cout << endl;

	cout << "emplace_back demo: " << endl;
	vector<Person> person2;
	cout << "Now start emplace_back" << endl;
	person2.emplace_back(22);

	system("pause");
	return 0;
}

测试结果:
在这里插入图片描述
结论2:

  • push_back:插入一个右值的时候,在push_back()函数内部,会先构造出一个新的临时对象,然后调用移动构造函数将这个对象放入容器末尾,最后析构掉这个临时对象;
  • emplace_back:插入一个右值的时候,在emplace_back()函数内部,会直接原地构造这个对象的同时直接插入,不会触发拷贝构造或者转移构造;
  • 注意C++11引入右值引用、转移构造函数之后,push_back()调用的是移动构造函数,而在这之前,都是调用的拷贝构造函数;
     

将实体类对象move()转右值之后传入

int main(int argc, char** argv) {
	cout << "push_back demo: " << endl;
	vector<Person> person1;
	Person p11 = Person(11);
	cout << "Now start push_back" << endl;
	person1.push_back(move(p11));

	cout << endl;

	cout << "emplace_back demo: " << endl;
	vector<Person> person2;
	Person p21 = Person(21);
	cout << "Now start emplace_back" << endl;
	person2.emplace_back(move(p21));

	system("pause");
	return 0;
}

测试结果:
在这里插入图片描述
可以看到与直接传入实体类的过程类似,只不过由于使用move()转成了右值,因此传参过程转移构造替代了拷贝构造过程;

vector扩容过程

测试代码如下:

int main(int argc, char** argv) {
	cout << "push_back demo: " << endl;
	vector<Person> person1;
	cout << "vector size = " << person1.size() << endl;
	Person p1 = Person(10);
	Person p11 = Person(11);
	cout << "Now start push_back" << endl;
	person1.push_back(p1);
	cout << "after insert p1, vector size = " << person1.size() << endl;
	person1.push_back(p11);
	cout << "after insert p11, vector size = " << person1.size() << endl;

	cout << endl;

	cout << "emplace_back demo: " << endl;
	vector<Person> person2;
	cout << "vector size = " << person2.size() << endl;
	Person p2 = Person(20);
	Person p21 = Person(21);
	cout << "Now start emplace_back" << endl;
	person2.emplace_back(p2);
	cout << "after insert p2, vector size = " << person2.size() << endl;
	person2.emplace_back(p21);
	cout << "after insert p21, vector size = " << person2.size() << endl;

	system("pause");
	return 0;
}

测试结果:

在这里插入图片描述

由于是直接传入实体类,因此push_back()和emplace_back()实现效果基本一致,以push_back()为例;

  1. 创建vector容器,此时容器大小为0;
  2. 构造出2个对象p1和p11:2次construct;
  3. 向vector中传入p1,调用拷贝构造(copy construct)将实体对象传递给push_back()中的形参;此时容器内部没有其他元素,因此直接扩容(一般认为是2倍),使用allocate分配器分配新的内存空间,将元素插入到末尾即可,插入后空间大小为1;
  4. 向vector中传入p11,调用拷贝构造(copy construct)将实体对象传递给push_back()中的形参;此时空间不足,需要扩容,使用allocate分配器分配新的内存空间;
  5. 此时由于容器内部已经存在一个元素p1了,因此,将原容器中的对象拷贝构造(copy construct)到新容器中,并且调用析构函数(destruction)将原容器中对象删除;
  6. 最后将新插入的元素p11放在容器末尾即可;此时容器大小为2;

注意:只要引起了vector空间的重新配置,指向原vector的所有迭代器都已失效。

问题: vector为什么是以2倍方式进行扩容而不是其他扩容方式?
答:2倍方式扩容,一方面可以保证扩容的时间复杂度为常数级,另一方面也不会申请过多的堆内存空间防止浪费;

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值